chrysn / aiocoap

The Python CoAP library
Other
262 stars 119 forks source link

How to simultaneously observe multiple resources? #343

Open WattageGuy opened 2 months ago

WattageGuy commented 2 months ago

Python version: 3.9.6 (default, Feb 3 2024, 15:58:27) [Clang 15.0.0 (clang-1500.3.9.4)] aiocoap version: 0.4.7 Modules missing for subsystems: dtls: missing DTLSSocket oscore: missing cbor2, cryptography, filelock, ge25519 linkheader: everything there prettyprint: missing cbor2, termcolor, pygments Python platform: darwin Default server transports: tcpserver:tcpclient:tlsserver:tlsclient:simple6:simplesocketserver Selected server transports: tcpserver:tcpclient:tlsserver:tlsclient:simple6:simplesocketserver Default client transports: tcpclient:tlsclient:simple6 Selected client transports: tcpclient:tlsclient:simple6 SO_REUSEPORT available (default, selected): True, True

My lwm2m client works to observe any resource on Leshan (lwm2m server) but not to observe 2 or more. Some times it works with two but its not stable, sometimes both resources gets the same value, in most case the seconds observe also gets the first observes value but not the other way around (as seen in the pictures).

Skärmavbild 2024-04-08 kl  15 27 48 Skärmavbild 2024-04-08 kl  15 27 44

I am pretty unexperienced but I have monitored the "Sending message" in message manager and the outgoing messages seems correct, correct value to correct resource. So I dont know where or why this happens. I have also changed one line in the resource.py to get the uri_path in the request. stripped = request.copy(uri_path=request.opt.uri_path)

This is my code handling the observe:

    async def handle_observe(self, request):
        path = request.opt.uri_path
        plen = len(path)
        if plen == 1:
            obs = f'observe_{path[0]}'
        elif plen == 2:
            obs = f'observe_{path[0]}_{path[1]}'
        elif plen == 3:
            obs = f'observe_{path[0]}_{path[1]}_{path[2]}'
        else:
            return Message(code=Code.BAD_REQUEST)

        def _notifier():
            self.updated_state(response=self.encoder.encode(path))

        try:
            obs_method = eval(obs)
            cancel = request.opt.observe == '0'
            _kwargs = dict(model=self.model,
                           path=path,
                           payload=request.payload,
                           content_format=request.opt.content_format,
                           cancel=cancel,
                           notifier=_notifier)
            obs_method(None, **_kwargs)
            print("Triggered observe")
            return self.encoder.encode(path)
        except NameError:
            pass
        return Message(code=Code.METHOD_NOT_ALLOWED)

    async def render_get(self, request):
        if request.opt.observe is not None:
            log.debug(f'observe on {"/".join(request.opt.uri_path)}')
            return await self.handle_observe(request)
        else:
            log.debug(f'read on {"/".join(request.opt.uri_path)}')
            return self.handle_read(request.opt.uri_path)`
WattageGuy commented 2 months ago

Some what related to https://github.com/chrysn/aiocoap/issues/146

WattageGuy commented 2 months ago

I did some Wireshark and I looks like /2 gets the value of /1 in the CON some times. When correct value is sent the packet has some 0HE value, no idea what this is.

Skärmavbild 2024-04-08 kl  15 59 20 Skärmavbild 2024-04-08 kl  16 02 38

And when wrong value (value from /1) it is -HE:

Skärmavbild 2024-04-08 kl  15 59 41

Edit: This seems to be the checksum

chrysn commented 2 months ago

Just to avoid confusion with other issues: This is unrelated to 146 (that is about the client side). This issue here is about the CoAP server side, which for some reasons LwM2M calls the client.

To help you here I'd have to understand what you are doing, and the code you copied in is insufficient for that. Do you have a pointer to your full source code?

WattageGuy commented 2 months ago

Okay sorry I dont know exactly what im doing, still trying to understand this CoAP stuff. Here is the project: https://github.com/WattageGuy/lwm2mclient-BLE-gateway

WattageGuy commented 2 months ago

Any clue yet @chrysn im in a bit of hurry with this project 😅

kwjones commented 1 week ago

@WattageGuy - Any progress on this issue? I'm seeing what I believe is the same anomaly. What I have noticed is that the tokens between more than one observation are being mis-assigned. Example, if I have an observation for battery_level that is using token "a1b1c1d1e1f1" and an observation for "current_time" that is using token "a2b2c2d2e2f2." It feels like updated_state() method may be mishandling this in some way. I'm thinking about creating a content message to replace the updated.state() message creation to see if that addresses the token handling.