husqvarnagroup / smart-garden-gateway-public

Open Source Components of the GARDENA smart Gateway
https://www.gardena.com/de/produkte/smart/smartsystem/
102 stars 13 forks source link

Best method for local control? #5

Closed DomiStyle closed 1 year ago

DomiStyle commented 1 year ago

Cool to see that Gardena has such a well documented open source repository.

I rooted a 19000 gateway and have SSH access to it, is it possible to locally control my garden mower?

I would like to control the mower from Home Assistant (Start, Stop, Status) without the cloud and before digging deeper into the protocols used I thought I would ask here.

broglep-work commented 1 year ago

We currently don't support controlling devices without the cloud. You can control the mower via cloud using our officially supported GARDENA smart system API or the unofficial home assistant integration that was built on it.

If you still see a need to control it locally, you should be able to find some tools on the gateway (such as nngforward and related systemd units) that help you achieve what you want. But it could still be challenging depending on the mower model and what aspects you want to control.

DomiStyle commented 1 year ago

Thanks for the response, I was not able to find nngforward on the latest firmware but I was able to achieve local control by directly posting start/stop UDP packets to the ppp0 interface. I was also able to get the status of the device from /var/lib/shadoway/work.

That should be sufficient for my needs.

Out of interest, is there any documentation on the values stored in the work directory?

{
        "address" : "",
        "id" : 4,
        "lemonId" : "4r",
        "timestamp" : 1680073114516,
        "uuid" : "014c2855-6196-4565-a468-c042c752ae26",
        "value" : "12.0"
}

There's a description for which id does what in the Value_description directory but it does not state which value represents what. I can take an educated guess but maybe they are noted somewhere?

broglep-work commented 1 year ago

In that case, you are not yet on the latest gateway software version. There is no public documentation on those values / device details and they can change at any time.

With the latest gateway software version you get some more descriptive names if you interact with the device on nng level instead of the lower level you are using right now (UDP / radio). But the information you can retrieve is essential same as you get from the mentioned files / folders

DomiStyle commented 1 year ago

Thanks! I let my gateway sit over night but doesn't seem to want to upgrade to a version that has nngforward installed.

I'm going to stick to the current variant since I only need to send start/stop anyway. I removed internet access for now so it doesn't upgrade anything and the values can't change.

easybe commented 1 year ago

Hi @DomiStyle

If you connect your gateway to the internet, I can try to find out why it has not been upgraded yet. You should really move to the latest software.

BTW, you can prevent files from being deleted during upgrades by adding their paths to /etc/sysupgrade.conf.

Cheers, Ezra

DomiStyle commented 1 year ago

Thanks for the offer! I bought the gateway used and seems it was never opened and had a really old software version and needed to update multiple times.

I started swupdate-check manually a few times and it updated successfully, nngforward is available now and I will take a look at it once I get some time.

BTW, you can prevent files from being deleted during upgrades by adding their paths to /etc/sysupgrade.conf.

That seems useful, thanks. Guess I can stop it from killing my SSH access on every update. ;)

rettichschnidi commented 1 year ago

That seems useful, thanks. Guess I can stop it from killing my SSH access on every update. ;)

This should not be needed. Setting dev_debug_allow_local_ssh in the U-Boot environment ensures that the local SSH access works across firmware updates:

# fw_setenv dev_debug_allow_local_ssh 1
easybe commented 1 year ago

This should not be needed. Setting dev_debug_allow_local_ssh in the U-Boot environment ensures that the local SSH access works across firmware updates

True, but he might want to persist the authorized_keys file.

@DomiStyle, setting the dev_debug_enable_nngforward U-Boot variable might also be interesting for you, it will allow you to send NNG messages to the gateway from within your LAN.

andrexp commented 1 year ago

Hi,

@DomiStyle, setting the dev_debug_enable_nngforward U-Boot variable might also be interesting for you, it will allow you to send NNG messages to the gateway from within your LAN.

How does this work? Is it only possible to send messages to the gateway or also receiving communication. For my understanding nngcat --bus --connect tcp://:28150-28153 should receive messages with connecting to one of the two nngforward instances. Unfortunately this does not work for me.

FredBit90 commented 1 year ago

Hi, When i set the variable dev_debug_enable_nngforward to 1, the services nngforward-lemonbeatd.service and nngforward-lwm2mserver.service are started after restart. These two services open TCP ports 28150 and 28151 for lwm2mserver, and 28152 and 28153 for lemonbeatd. The first attempts to capture something on these ports were unsuccessful. At /usr/bin/nngforward is the shell script which is used for the nngforward services. An analysis of the script showed that the opened ports 28150-28153 are only set as INPUT in the firewall. If the quiet mode of the nngforward services is disabled (remove -q when calling the service) you get an output with the socat commands to use in your client.

Screenshot 2023-04-16 083418

If you use the socat commands directly as shown and send data to one of the 4 ports then you have built a loop. If you set up the forwarding to your own tcp server instead, you will see the data you send to one of the four ports in your own server. The nngforward service forwards the incoming data on the ports to the file /tmp/lwm2mserver-command.ipc, /tmp/lwm2mserver-event.ipc, /tmp/lemonbeatd-command.ipc and /tmp/lemonbeatd-event.ipc. If you enable the additional redirects mentioned from the service output, the data written to the mentioned files will be redirected to the self-selected endpoint. so far so good. As I understand it, with the nngforward service we have by default a service to write data to the file that the actual services lwm2m and lemonbeatd work with it?!?! Now I would have thought that if I trigger an action via the Gardena app, the respective command also ends up in one of these files and is therefore visible in the own endpoint when forwarding is active. Unfortunately, one gets here nothing to see.

easybe commented 1 year ago

You will see something if you subscribe to ipc:///tmp/lemonbeatd-event.ipc with topics="". For Python, you can find the documentation here.

FredBit90 commented 1 year ago

You will see something if you subscribe to ipc:///tmp/lemonbeatd-event.ipc with topics="". For Python, you can find the documentation here.

Thank you for your reply @easybe.

I create a small python script to subscribe the events

import time
from pynng import Pub0, Sub0, Timeout

with Sub0(dial='ipc:///tmp/lemonbeatd-event.ipc', recv_timeout=20000) as sub0:
        sub0.subscribe("")
        print(sub0.recv())

and i will get the following output after starting the script two times when i park my lawnrobot in the gardena app

root@GARDENA-1f997d:~# python3 test.py
b'[{"entity":{"device":"XXXXXXXXXXXXXXXXXXXX","path":"lemonbeat/0"},"metadata":{"sequence":47,"source":"lemonbeatd"},"op":"update","payload":{"mower_timer":{"ts":1681655800,"vi":0}}}]'
root@GARDENA-1f997d:~# python3 test.py
b'[{"entity":{"device":"XXXXXXXXXXXXXXXXXXX","path":"lemonbeat/0"},"metadata":{"sequence":50,"source":"lemonbeatd"},"op":"update","payload":{"internal_connection_state":{"ts":1681655804,"vi":3}}}]'

When i subscribe the lwm2mserver-event.ipc i will get no output.

Is it possible to receive the data of the lemonbeatd-command.ipc file as well? I get no output when i subscribe the ipc file. Or can i directly publish a message in the shown format to the lemonbeatd-command?

broglep-work commented 1 year ago

Note that you can't directly use nng with tcp transport to connect to those ports exposed, instead use the mentioned socat commands from the nngforward command and execute them on your own machine or server, this essentially mirrors the nng sockets from your gateway to your own machine. You can then interact with the nng sockets as you would be on the gateway using the inter-process transport.

The command sockets are request/reply as opposed to the event sockets (which are pub/sub)

Intercepting requests from other components on the gateway is likely not that easy. You will be better off looking at enabling debug mode and/or increase verbosity via command line flags on the gateway components in question (e.g. cloudadapter) so that the commands received are logged.

andrexp commented 1 year ago

Note that you can't directly use nng with tcp transport to connect to those ports exposed, instead use the mentioned socat commands from the nngforward command and execute them on your own machine or server, this essentially mirrors the nng sockets from your gateway to your own machine. You can then interact with the nng sockets as you would be on the gateway using the inter-process transport.

The command sockets are request/reply as opposed to the event sockets (which are pub/sub)

Thank you for making this clear. I now understand.

Intercepting requests from other components on the gateway is likely not that easy. You will be better off looking at enabling debug mode and/or increase verbosity via command line flags on the gateway components in question (e.g. cloudadapter) so that the commands received are logged.

Is there any documentation which command line flags are existing? With /usr/bin/cloudadapter(_native) --help or -? no output is generated.

broglep-work commented 1 year ago

Is there any documentation which command line flags are existing? With /usr/bin/cloudadapter(_native) --help or -? no output is generated.

--help or -h should work (note that it might take some time until component is being started on the gateway)

The flags that should you get the logs of the received commands is -vv

andrexp commented 1 year ago

Thank you, we now see debug information. Also the sending of commands via pynng and Req0 to ipc:///tmp/lemonbeatd-command.ipc seems to be successful. Unfortunately we did not manage to connect to Rep0 to ipc:///tmp/lemonbeatd-command.ipc (Error: Address already in use).

Do you have any example for us?

broglep-work commented 1 year ago

Unfortunately we did not manage to connect to Rep0 to ipc:///tmp/lemonbeatd-command.ipc (Error: Address already in use).

You don't need Rep0, this is the other side of the Req/Rep pair. You only need the Req0 and write to that socket to send a request and then read from that socket to receive the response. You can find an example in the pynng documentation (that example implements both ends)

FredBit90 commented 1 year ago

Thank you for your hints @rettichschnidi @easybe @broglep-work.

We (@FredBit90 @andrexp) have successfully created a basic python script for communication to an own MQTT Broker.

You can use Version 1.0.1.0

FredBit90 commented 1 year ago

We want to translate the state and lasterror values from the lemonbeat service to a description. We have already translate some codes through testing with the lawnrobot in the garden. The first idea was to use the MowerError Enumeration which is documented in the husquarna developer portal:

grafik

When i count up the enumeration starting at value 0 then you can see that value 10 equals with the documentation. We find out that for example value 15 is error lifted. In the documentation lifted is on zero based position 14 following on stuck_in_charging_station and charging_station_blocked.

The idea is that zero based values 0 to 11 equals with the API documentation. Error 12 in original documentation is no_drive. Is it possible that these error is not included in the Lemonbeat error enumeration, resulting in this shift?

Are there any documentation for the state values? In the API documentation only the MowerActivity enumeration is included, which is not comparable to the state enumeration or shows any relation to it.

grafik

broglep-work commented 1 year ago

There is no public documentation for those low level values and I can't help you with that unfortunately.

The reason why the API documentation does not match with what you observe on the lower level is because the officially supported API provides a conversion / compatibility layer so that all mowers can be controlled with a single interface. Internal values can be different for different mower models and the values can also change across firmware versions. You might be able to re-construct a mapping for your particular mower model & firmware version if you are using the developer API and correlate the developer API values with the internal values (e.g. pause mower via API and then check the internal values)

I'll close this issue here as we are getting a bit off topic now, this issue here regarding best method for local control has been resolved by now