Ezlo device state events?

Yes, it is. I can’t run your python code, it just exits immediately with no output.

Thanks - I suspected it might be. From my testing, Javascript handles web sockets differently. It doesn’t need to “talk” to the server at the “user level” (or is doing so behind the scenes)… A ping/pong seems to be sufficient.

Here’s a more complete Python example if you want to try it.

# WS client example
# Listens to broadcast events from the Ezlo hub


import asyncio
import websockets

async def wsListener():

    uri = "ws://192.168.1.176:17000/"
    while True:
        async with websockets.connect(uri) as websocket:
            greeting = await websocket.recv()
            print ("Hub says: " + greeting)
            await asyncio.sleep(0.5)


def startListener():
    loop = asyncio.get_event_loop()

    try:
        asyncio.ensure_future(wsListener())

        loop.run_forever()

    except KeyboardInterrupt:
        pass
    finally:
        loop.close()
        

def main():
    print ("Starting hub listener")
    startListener()


# The main entry point for our app.
if __name__ == '__main__':
    main()

This will let you listen to hub broadcast events.

any help you might need, we are here for you guys. Just let us know if we need to expand the API, happy to expand it.

I’ll give it a go later. My test on an insecure channel with anonymous access just concluded at over 20 hours continuous with no data moving other than ping/pong. I wonder if this is something specific to the Python implementation, because I can confirm by my own network monitoring that there’s no other data on channel (nothing going on “behind the scenes”). I’m also going to try it with my Lua WS implementation (LuWS) and see what happens. Stay tuned.

Thanks - overall the API is excellent. It’s fast, comprehensive, but here’s the biggest “issue” I see so far… the deviceIDs and _ids.

Here’s an example:

To get the devices, you call:
hub.devices.list

It returns (among other things) a device id (_id). But this is NOT the id used to control the device.

To get that, you then have to call hub.items.list

And then you have to map the _id from hub.devices.list to the deviceId in hub.items.list to get another _id which is then used to control the device.

This requires multiple APIs calls to perform some actions.

It seems that all APIs call that deal with devices should all have a single / primary id. (Or am I missing something).

Thanks - I can’t tell (yet) if it’s a Python “issue” or a Javascript “feature”. With Python you have to send user-level requests to keep the connection alive (even with ping/pong) but with Javascript a ping/pong alone appears to be sufficient.

Look at hub.data.list, which can return a more comprehensive set of data in a single request.

Thank you. Oddly, I don’t see it in the API tool, or the API docs - how did you find it?

Do you know what the params / JSON are?

I’m getting:

"{"error":{"code":-32602,"data":"rpc.params.invalid","message":"Wrong params","reason":"No collection names passed"},"id":"60e8837c077e90401a656017","result":{}}"

Yeah, it’s tucked in an odd corner: Common - Ezlo API Documentation

Excellent. Thank you. I’ll take a closer look.

I really wish you could search the results in the API Tool. Or they would change the results output so the friendly device names are displayed first.

I have 102 devices on my Ezlo Plus and trying to find one particular device in that list, to then try and find its _id for say the “Switch” item is a nightmare.

I just finished about a 45 minute run on your code with no disconnect/stall. I was running on Ubuntu 20.04.2 (under VMWare) with Python 3.8.10, websockets 9.1, asyncio 3.4.3. I’ve just started another test with more careful timing measurement. The hub is dead quiet (no activity/testing/development going on during these tests) other than a single manipulation of a switch at the start to make it send a ui_broadcast to confirm the app is actually connected.

1 Like

is @rigpapa 's help resolved this issue for you @robotman ?

I must say I also tested @robotman’s first ping/pong code and didn’t get any disconnection. I tried several times for over 2 hours time intervals.

Interesting… it definitely disconnects (freezes on my end), unless I add a hub-level query. Difficult one to track down… be curious what other users get if they try it.

Not sure yet - I’ll have to gibe the other API a try. I’ll let you know. (That being said, the id, deviceId thing is still a challenge).

As I understand it, you have to use the ID number of the “item” not the devices actual device ID.

A device may have several different items that can be controlled, like switch, dimmer, rgb etc.

So in the API call you have to specify the item ID of say the “Switch” if thats the part of that device you want to control.

Hello @robotman,

  1. We are controlling items because devices has multiple control items which represents different functionality, especially thermostats, doorlocks, etc

  2. Each item has deviceId it belongs to. “deviceId”: “5f2df55446a3d010907fca7e”,

 "method": "hub.items.list",
    "result": {
        "items": [
            {
                "_id": "5f2df55546a3d010907fca7f",
                "deviceId": "5f2df55446a3d010907fca7e",
                "hasGetter": true,
                "hasSetter": false,
                "name": "electric_meter_amper",
                "scale": "ampere",
                "show": true,
                "value": 0,
                "valueFormatted": "0",
                "valueType": "electric_current"
            },
  1. You can just apply a filter to receive all items that belong to the particular device.
    Here is the regular request:
{
    "method": "hub.items.list",
    "id": "_ID_",
    "params": {}
}

Which returning ALL items from all included devices.

And here is request with the filter for “deviceId”: “5f2df55446a3d010907fca7e”

{
    "method": "hub.items.list",
    "id": "_ID_",
    "params": {
        "deviceIds": [
            "5f2df55446a3d010907fca7e",
        ]
    }
}
In general request with filter by deviceId looks like this:
{
    "method": "hub.items.list",
    "id": "_ID_",
    "params": {
        "deviceIds": [
            "deviceId0",
            "deviceId1"
        ]
    }
}

all information about these requests is available here:
https://api.ezlo.com/hub/items_api/index.html#hubitemslist
https://api.ezlo.com/hub/devices_api/index.html#hubdeviceslist

Write please if you have any other questions about hubs API.

OK… nearly five hours using your Python code as previously reported, and no messages, didn’t disconnect.

1 Like

Hi @robotman,

Let me add several things about our API:

  1. We have 3 types of entities representing physical devices: logical devices, items, device settings.
  2. Logical device is just a container with functionality. The functionality of the device is represented by items and settings. As usual, items are enough for typical device managing; settings are used for deeper customization.
  3. Physical device can have several functionalities under the hood (E.g. sensor device with motion sensor and the smoke sensor inside or multichannel plug with several outputs; etc…). So we split these sub functionalities: physical device can be divided into several logical devices. Each included physical device has a root logical device, other logical devices are children. Look at the field “parentDeviceId”. It’s empty for root and not empty for children.
  4. Each logical device contains a set of functionality representing by items (each logical device has one or more items). Take the field “deviceId” to match the item to the device. Once again: an item is a simple but holistic element of the functionality (switch, sensor, thermostat setpoint, doorlock state, etc…), the logical device can have a set of items. The principle is the same for device settings (except that only the root logical device has settings).
  5. If the user of firmware API just has started his application, he should request hub.devices.list, hub.items.list, hub.device.settings.list and build own UI model depend on his application purposes. Then it’s not necessary to request all these things each time, better listen to broadcasts.
1 Like