Help needed creating a custom Hub Component

Thanks. I did try using websocket client, but ws4py (https://ws4py.readthedocs.io) seems to work a bit better.

I can send and receive messages using that, but I am more interested in what I need to do to integrate with HomeAssistant and how that works.

Take a light for example. Here are the three things that I need to accomplish.

  1. Discover the lights. The API will allow me to get a list of devices, I can iterate through the list and fetch only the lights. Now how do I send this to HASS

  2. Communicate state changes - Since its a constant connection I can get the state changes. I am trying to understand if HASS polls for any state change or does my script have to push the state change to HASS.

I think these are pretty basic questions, but I am unable to get the answers I need to come up with something from scratch. Any pointers would be appreciated.

Home assistant is in the process of moving to async instead of using threads. By doing so it will probably start using aiohttp for all internet communication including web sockets. I don’t know when this is all going to happen, but I am pretty sure this will be the future proof way of doing this…

It has taken me hours of study and experimentation but I think I have this figured out. It wasn’t easy as I am new to python too.

My implementation uses telnet to listen and talk to the Lutron Caseta Pro hub, your implementation my use a built in protocol or stack. You need to study the python libraries for asyncio (asynciolib) and how to add to the event loop in HA with coroutines. zone.py in the components directory is a good place to study as, they are using the basic functionality. Once I have the bugs wrung out on my code I will make it available.

Thank you. This is what I was looking for. I’ll look at zone.py as well as your code when you release it.

Sorry about this but I have different answer now. After attempting to use the the event loop which utilizes asincio, appeared to be real stable, I had issues with future and exceptions. I have changed my methodology to a much simpler method. when using “hass.bus.listen_once(EVENT_HOMEASSISTANT_START, my_running_function)” I discovered that the function is started in i’s own thread so I just used a “while self.I_am_running” type loop with “time.sleep(self.interval)” in the loop to set my loop rate. Then a stop function which runs in a different thread can be used to turn off “self.I_am_running” which will stop the loop. This is simple but, I am finding that the timing in the loop stutters a bit since I run mine at 6 to 8 per second to read the switches. This is at least stable, handles the hub going offline and reconnecting and can be stopped and restarted.

If anyone has any input on dealing with this in the event loop using an outside socket handler (I am using telnetlib), I would like to hear it.

I too have a Almond+ and would like to use it as a bridge. I started googling and found this thread and another one you started https://community.home-assistant.io/t/newbie-hass-component/25826?u=penright. The other was newer but this had more activity. Which one?
I am a .NET guy, but can I speak other languages. :slight_smile: I am willing to help.

So I have two questions:
@kdvlr Where are you at on this project?
Anyone else interested?

I could not get around to creating a proper component, but ended up using command line sensors and switches. I have uploaded those very crude scripts into github here - https://github.com/kdvlr/almond-scripts/ That should get you started

So are you still using your Almond+ for home automation task?

Just started digging, but here is where I am at right now.
Somehow I find myself looking at …

As stupid as this sounds, I never really understood the HA architecture. Guess I still don’t. :slight_smile:
Anyway, we do not want to do a “component”, we want to do a “platform”.

Using Wink as an example …
Starting with the switch …
Here is the code …
https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/switch/wink.py
There are not that many lines. Just enough to wire the switch components properties to the Wink API.
Then the heavy lifting is in the Wink API …

So, I first step is to create a API. Is the Almond+ API same as the other Securfi products or do we need to drill down into Almond+

I need to get to my day job. Thoughts?

Thanks, quick question. I am trying to set up the environment to test. Is there a URL example I can test with from a browser so see if I am connected easily? If so what would the device list look like?

<Almond_IP:7681/root/?“MobileInternalIndex”:“device_list_231234”,“CommandType”:“DeviceList”

The easiest would be to use a websocket client for the browser. Search for websocket client for firefox or chrome.

Here are the steps

  1. Get the websocket client and add it to your browser.
  2. Go to ws://10.10.10.254:7681/root/frank . Replace the IP with your Almond IP if that is different. Change frank to your password
  3. It should respond back with something.
  4. Now type this as a test

Request
{
“MobileInternalIndex”:“3424324234”,
“CommandType”:“DeviceList”
}

  1. This should give you a list of all your devices.

Had to add an extension to my chrome browser. I used https://chrome.google.com/webstore/detail/smart-websocket-client/omalebghpgejjiaoknljcfmglgbpocdp?hl=en

Was able to see the response. All that worked. Next step is a hello world python program. I have a mac at home and I am not a mac person. That step may take longer than it should seem. At least now, thanks to you, I can verify that the A+ is responding.

@kdvlr Do you what does the request look like to turn on/off say a switch?
Looks like I set set the name https://wiki.securifi.com/index.php/Websockets_Documentation

FWI, I asked the same question on the Securifi form … https://forum.securifi.com/index.php/topic,6101.0.html

Here’s a sample I use to dim my lights.

This turns it off.

 ws.send(str('{ "MobileInternalIndex":"dim_lights_hass", "CommandType":"UpdateDeviceIndex", "ID":"45" "Index":"1","Value":"0" }'))

This sets it to 40%

    ws.send(str('{ "MobileInternalIndex":"dim_lights_hass", "CommandType":"UpdateDeviceIndex", "ID":"45" "Index":"1","Value":"40" }'))

Let me know if that works.

Thanks. How did you connect the dots on that looking at the API?
I guess whatever key/value you include gets updated?
So Value is the key and 0 or 40 is the value.

Here is one of my binary switches

"9": {
      "Data": {
        "ID": "9",
        "Name": "Power Strip 1",
        "FriendlyDeviceType": "BinarySwitch",
        "Type": "1",
        "Location": "Default",
        "LastActiveEpoch": "1521894543",
        "Model": "ZFM-80",
        "Version": "4",
        "Manufacturer": "Remotec"
      },
      "DeviceValues": {
        "1": {
          "Name": "SWITCH BINARY",
          "Value": "false",
          "Type": "1"
        }
      }

So I would expect

{"MobileInternalIndex":"123", "CommandType":"UpdateDeviceIndex", "ID":"9","Index":"1", "Value":"true"}

To turn it on. Do you agree?

Here is my response

{
  "MobileInternalIndex": "123",
  "CommandType": "UpdateDeviceIndex",
  "Success": "true"
}

Edit: I just remembered seeing it maybe unplug. I will test this when I get home. Stand by.

Yes. That should work. You can also do a device list to see if the value has been updated.

It worked. It was not plugged in. :slight_smile: Just because it return true does not mean to took effect. Looks like we need to query after an update to see if the state changed.

I was typing my response when you sent yours :slight_smile:

Thanks. I was looking at the API doc and thought the example was the only choice. I started the code as a library to HA. Right now I have a CLI entry point so I can run the API from a command line. Right now phase 1 is reading. Next is updating.
What is taking so long I am learning python and git as the repository.
Have you had a chance to look at it yet? Right now I am still updating the master branch till I get the ability to read and update. Then I will start to look at building the component.

I saw the repo. That’s pretty good so far. I tried building a proper component with full support, but the Home assistant document was not great back then. I see that the developer site is much better now.
I don’t think I will have the time, but I will try and help as much as I can.

Thanks for your time. Your comments have help me connect the dots on where we need to go. We are going to get there :slight_smile:

Last night and this evening I have been spending time with asyncio.
I have a gap in python right now. I getting ready to redo the api and make more event driven. Right now it is still synchronous in it sends a message and waits for the response.
I was using a websocket plugin for chrome (Smart Websocket). So I left it connected while I was typing. When some of my rules started firing, the response was showing up! That when it dawn on me 1. I did not know enough python yet to handle asynchronous messages and 2. why the API need to be separate of component.
I say all this at my current understanding, asyncio is all running in the same thread. Good news when you are waiting for an I/O the thread is yielded, so now other code can run, but if something is blocking then the thread stops.
So…
My next task is to finish wrapping the API with a shell I can run from the command line to test it. I am starting to see how I need to handle asynchronous events. I finally connected the dots that my devices can generate a message all on their own. So I am going to redo the API so send and receive are two different functions. The command to turn on a light will send a message and I may queue that it was sent, so as to match the response and know if a sent message with a command or was someone turning on the light.

@kdvlr Thought I would throw out a quick update. I feel pretty comfortable commanding the A+ and consuming the events. I have been hung on python learning for awhile now. The library I was using is Websockets and it is asyncio based. I been trying to spin it off into another thread and that is where I been having problems. If my main() starts the event_loop (asyncio.get_event_loop().run_until_…) I can communicate all I want.

But, If I try and start it in a different thread, so I can control the API from the outside, that is where I run into issue. I kind of burned out my welcome on the dev chat. My first question was on topic, but then it went more into them teaching me python. For now I have stuck a pin understanding hass code and focus on getting the api not to block and calls. On the dev chat they said you can’t use asyncio and threads together. I assumed they were saying not together at my level of python understanding. Since Websockets is asyncio based, I guess I need a different library.

Just curious what is your “python understanding” level?
What are you using for websocket library?
I am going to post some links to threads in the python forum where I was looking for answers. It might trigger someone thinking here …
https://python-forum.io/Thread-Pro-s-and-Con-s-of-some-different-websocket-libraries
https://python-forum.io/Thread-Trying-to-understand-blocking-in-both-multitasking-and-asyncio

Here is some test code where I was launching the event_loop in a different thread. For some reason even if in a different thread, as soon as I run the event_loop it blocks other threads.
Here is an example code to demonstrate where threads are getting blocked.
The post has two modules and the output. The CLI is my command line interface and it creates an instance of a Test class. That class is representing my A+ api. Right before I go into a loop that represents my code that will control the API, I start the event_loop required for the websockets. ‘a = Test(f), a.start()’. Inside the a.start() is where a thread is created for the event_loop. The thread does start and the event loop does block the thread as I would expect. But it also blocks the other threads also. I did not expect that. Maybe I am creating threads wrong.

As posted the event_loop is rem out in the loop_helper function.
There are two way of lunching the main(). 1. is by an entry point created with “setup.py devlop”, the second is running it from the interpreter. Right now I an testing in PyCharm.
All work functions are a series of prints to show work is being done. There are three threads started from main() and the main() has a loop with prints to show work after the threads are started. Since each function is in it’s own thread, I expect that they will not block each other, including the loop in the main(). There is the class “Test” that starts a event_loop (more details below) from the main(). If it works the event_loop will run a function that does a loop of prints to show work.
When the event_loop is no longer rem out, I expect the loop_helper() to print “test from helper” and return, then the start() print “Receiver running” and return. Then the main() will fall into it’s loop. It does not. The loop.run_until blocks the main thread. The other threads started run as expected.
Why does it block the main() and how can I start the event_loop where it does not block the main()?

Here is the boiled down code and output. If I can get the event_loop to run and not block the other threads, I can make the API work.
https://hastebin.com/qayataqoxi.sql