beveradb / sonoff-lan-mode-homeassistant

Home Assistant platform to control Sonoff switches running the latest Itead firmware, locally (LAN mode).
MIT License
74 stars 36 forks source link

Sonoff basic state does not update if controlled by device's button #7

Closed tota-5 closed 5 years ago

tota-5 commented 5 years ago

If the state of the switch changes via a button press on the physical device, this state is not reflected in HA.

Steps to reproduce: -Setup a sonoff basic in HA with LAN support; -Press the sonoff black button on the device; -Sonoff switch state does not update on HA;

Expected: -States should be correctly shown in HA independent on what caused the change;

tota-5 commented 5 years ago

I will get the android packagen sniffer and post here the dump as soon as I get home. For what I read in the code, there isnt a 2 way communication happening, only the one via HA -> Sonoff basic.

If the state changes via switch, there is nothing listening to it in the component side to reflect it in HA.

The way I got to this issue was by setting up a wall switch, and pressing the button expecting my lights to toggle (i've implemented triggers in HA to chain the lights events when the switch changes state), and found out that the sonoff -> HA communication isn't there.

beveradb commented 5 years ago

You're totally right, and I already knew this was the case in the back of my head, I was just lazy and implemented only the bare minimum to get the switch toggling! Since my Sonoff is installed behind a light cluster there was never a use case for me to press the hardware button.

This is definitely something we should implement in this component, but it'll probably need a little bit more work/research to get it working properly as the component will presumably need to hold on to a persistent websocket connection with the device so it can receive state update messages.

tota-5 commented 5 years ago

I'm definitely down to help here! I got all the setup ready for testing. Hassio running on a raspy, the button close to the computer, and all components set and working!

I will be online today latter.

I could do it all myself if I only knew a little bit more about sockets, connection, etc...

Im guessing we will leave a listener function up per switch, and im guessing HA has a callback for state updates that I can call once a msg is recieved in this listener...I just need to better understand what method listens what, and how to write it.

Im taking a look at all of this right now, but since im away from home in the moment, im just speculating =]

tota-5 commented 5 years ago

i did some packet sniffing, and as this is my first time doing this, i looked for stuff that had the ip or mac adress of the sonoff i was testing, i got just one in a test where i purelly pressed the switch with the app running using the android sniffer you suggested.

I'll attach the result and provide information for you to filter, since i have no idea how to work most of this stuff.

link to the pcap: https://drive.google.com/file/d/12CmVYf0Gj_bALgZiUmlh5f25VQL1NkD1/view?usp=sharing

Main informations: I have 5 sonoff running, all of those have reserved ip adresses.

ips with mac: ESP_94D16C DC-4F-22-94-D1-6C 192.168.0.112 ESP_8F5C75 DC-4F-22-8F-5C-75 192.168.0.113 ESP_928C23 DC-4F-22-92-8C-23 192.168.0.114 ESP_8F5F42 DC-4F-22-8F-5F-42 192.168.0.115 ESP_928AB6 DC-4F-22-92-8A-B6 192.168.0.116

I saw this pack part in particular:

Extended Payload length (16 bits): 145
Payload

Line-based text data (9 lines) {\n "userAgent":"device",\n "apikey":"b9c9da8f-0cfc-4fe6-9ec4-21b03297cbde",\n "deviceid":"100060af40",\n "action":"update",\n "params":{\n "switch":"on"\n }\n }

Think we can extract something out of this?

EXTENDED PACK DATA:\/

Frame 222: 315 bytes on wire (2520 bits), 315 bytes captured (2520 bits) Encapsulation type: Ethernet (1) Arrival Time: Jan 21, 2019 22:27:25.945762000 Hora Padrão de Caracas [Time shift for this packet: 0.000000000 seconds] Epoch Time: 1548124045.945762000 seconds [Time delta from previous captured frame: 0.000457000 seconds] [Time delta from previous displayed frame: 0.000457000 seconds] [Time since reference or first frame: 10.280186000 seconds] Frame Number: 222 Frame Length: 315 bytes (2520 bits) Capture Length: 315 bytes (2520 bits) [Frame is marked: False] [Frame is ignored: False] [Protocols in frame: eth:ethertype:ip:tcp:http:websocket:data-text-lines:data-text-lines] [Coloring Rule Name: TCP] [Coloring Rule String: tcp] Ethernet II, Src: Google_00:00:01 (00:1a:11:00:00:01), Dst: Google_00:00:02 (00:1a:11:00:00:02) Destination: Google_00:00:02 (00:1a:11:00:00:02) Address: Google_00:00:02 (00:1a:11:00:00:02) .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default) .... ...0 .... .... .... .... = IG bit: Individual address (unicast) Source: Google_00:00:01 (00:1a:11:00:00:01) Address: Google_00:00:01 (00:1a:11:00:00:01) .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default) .... ...0 .... .... .... .... = IG bit: Individual address (unicast) Type: IPv4 (0x0800) Internet Protocol Version 4, Src: 192.168.0.112, Dst: 10.8.0.1 0100 .... = Version: 4 .... 0101 = Header Length: 20 bytes (5) Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT) Total Length: 301 Identification: 0x014c (332) Flags: 0x4000, Don't fragment Time to live: 16 Protocol: TCP (6) Header checksum: 0x9d5e [validation disabled] [Header checksum status: Unverified] Source: 192.168.0.112 Destination: 10.8.0.1 Transmission Control Protocol, Src Port: 8081, Dst Port: 40062, Seq: 160, Ack: 621, Len: 261 Source Port: 8081 Destination Port: 40062 [Stream index: 13] [TCP Segment Len: 261] Sequence number: 160 (relative sequence number) [Next sequence number: 421 (relative sequence number)] Acknowledgment number: 621 (relative ack number) 0101 .... = Header Length: 20 bytes (5) Flags: 0x018 (PSH, ACK) Window size value: 65535 [Calculated window size: 65535] [Window size scaling factor: -2 (no window scaling used)] Checksum: 0x21a9 [unverified] [Checksum Status: Unverified] Urgent pointer: 0 [SEQ/ACK analysis] [iRTT: 0.008029000 seconds] [Bytes in flight: 261] [Bytes sent since last PSH flag: 261] [Timestamps] [Time since first frame in this TCP stream: 0.280412000 seconds] [Time since previous frame in this TCP stream: 0.053386000 seconds] TCP payload (261 bytes) [PDU Size: 112] [PDU Size: 149] WebSocket 1... .... = Fin: True .000 .... = Reserved: 0x0 .... 0001 = Opcode: Text (1) 0... .... = Mask: False .110 1110 = Payload length: 110 Payload Line-based text data (1 lines) {"error":0,"apikey":"09a15816-c289-4333-bf7b-aa52ffafdf96","sequence":"1548124045842","deviceid":"100060af40"} WebSocket 1... .... = Fin: True .000 .... = Reserved: 0x0 .... 0001 = Opcode: Text (1) 0... .... = Mask: False .111 1110 = Payload length: 126 Extended Payload Length (16 bits) Extended Payload length (16 bits): 145 Payload Line-based text data (9 lines) {\n "userAgent":"device",\n "apikey":"b9c9da8f-0cfc-4fe6-9ec4-21b03297cbde",\n "deviceid":"100060af40",\n "action":"update",\n "params":{\n "switch":"on"\n }\n }

beveradb commented 5 years ago

Awesome, thanks for sharing that packet dump!

So, there's nothing I haven't seen before from my own packet dump in that one (e.g. no multiple outlets or other parameters like the other issue thread), though it's certainly interesting to see multiple devices managed by the same eWeLink app so we can see what values are different.

Just as a heads up, here's a screenshot showing the filter I applied in WireShark to see all of the WebSocket traffic.

If you filter for a single IP (ip.addr == 192.168.0.112 and websocket), open the "Line-based text data" node in the bottom window and scroll down the entries, you can see the full communication between the app and a single device:

  1. The app tells the device it is online and listening for updates:
    {
    "action": "userOnline",
    "ts": "1548124045",
    "version": 6,
    "imei": "2830950fdaf4b458",
    "model": "SM-G955F_universal8895",
    "os": "Android",
    "romVersion": "8.0.0",
    "at": "b6368f49d2e6f17b0de3062a124bc97d63422ca7",
    "appid": "oeVkj2lYFGnJu5XUtWisfW4utiN4u9Mq",
    "nonce": "et1giini",
    "apkVesrion": "4.2",
    "apikey": "b9c9da8f-0cfc-4fe6-9ec4-21b03297cbde",
    "sequence": "1548124045842",
    "userAgent": "app"
    }
  2. 6 seconds later, you press the button on the switch so it sends a state update message on the websocket:
    {
    "userAgent": "device",
    "apikey": "b9c9da8f-0cfc-4fe6-9ec4-21b03297cbde",
    "deviceid": "100060af40",
    "action": "update",
    "params": {
    "switch": "on"
    }
    }
  3. Then, every 5 seconds we get "ping" / "pong" messages sent by both the switch and the app, presumably to both keep the connection alive and ensure both sides know they are still connected and online:
    {
    "ping": "ping"
    }
    {
    "pong": "pong"
    }

I'm creating a test script just now to do the same thing from python - I'll let you know when it's ready to run to test yourself!

tota-5 commented 5 years ago

Thank you so much! Ill run it as soon as I get home! Thank you for helping me understand this! Next dump comes with a filter!

tota-5 commented 5 years ago

I saw you committed a test script with the listening method! I'll test it in a bit and give you logs!

beveradb commented 5 years ago

Sorry I didn't have anything for you to run when you got home - I've only just finished getting this to the point where it's usable.

We've now got a test script, in python, which implements most of a "proper" websocket client for interacting with Sonoffs in LAN mode: test_sonoff.py

So far I've only tested this with the mock script I also committed, but I'm reasonably confident that the mock script was replicating the basic Sonoff correctly as I'm using strings directly from real packet dumps.

To run it, all you should need to do is edit it to replace localhost with one of your Sonoff IPs, and run with python test_sonoff.py (or python3 depending on your environment).

Here's an example of the output I get when running against my mock server, which simulates a user pressing the physical switch button on the Sonoff 10 seconds after connecting:

andrew@thinkpad : sonoff-lan-mode-homeassistant $ python3 test_sonoff.py
2019-01-22 23:44:14 - DEBUG - Sonoff class initialising
2019-01-22 23:44:14 - DEBUG - initializing websocket
2019-01-22 23:44:14 - WARNING - WebsocketListener initialising...
2019-01-22 23:44:14 - WARNING - WebsocketListener initialised
2019-01-22 23:44:14 - DEBUG - attempting to call WebSocketApp run_forever with ping_interval: 145
2019-01-22 23:44:14 - DEBUG - sending user online websocket msg: {"apkVesrion": "1.8", "apikey": "apikey", "model": "iPhone10,6", "sequence": "1548200654316331", "action": "userOnline", "at": "at", "userAgent": "app", "os": "ios", "nonce": "349297597422982", "version": 6, "ts": "1548200654", "romVersion": "11.1.2"}
2019-01-22 23:44:14 - DEBUG - received websocket msg: {"error": 0, "sequence": "1548124045842", "apikey": "09a15816-c289-4333-bf7b-aa52ffafdf96", "deviceid": "100060af40"}
2019-01-22 23:44:14 - DEBUG - received hello from deviceid: 100060af40, no action required
2019-01-22 23:44:15 - DEBUG - received websocket msg: {"deviceid": "100060af40", "params": {"switch": "off"}, "apikey": "09a15816-c289-4333-bf7b-aa52ffafdf96", "userAgent": "device", "action": "update"}
2019-01-22 23:44:15 - INFO - received action: update
2019-01-22 23:44:15 - DEBUG - found update action in websocket update msg
2019-01-22 23:44:15 - DEBUG - found switch/switches in websocket update msg
2019-01-22 23:44:15 - DEBUG - searching for deviceid: [] in known devices 100060af40
2019-01-22 23:44:15 - DEBUG - device not found in known devices, adding
2019-01-22 23:44:25 - DEBUG - received websocket msg: {"deviceid": "100060af40", "params": {"switch": "on"}, "apikey": "09a15816-c289-4333-bf7b-aa52ffafdf96", "userAgent": "device", "action": "update"}
2019-01-22 23:44:25 - INFO - received action: update
2019-01-22 23:44:25 - DEBUG - found update action in websocket update msg
2019-01-22 23:44:25 - DEBUG - found switch/switches in websocket update msg
2019-01-22 23:44:25 - DEBUG - searching for deviceid: [{'apikey': '09a15816-c289-4333-bf7b-aa52ffafdf96', 'action': 'update', 'userAgent': 'device', 'deviceid': '100060af40', 'params': {'switch': 'off'}}] in known devices 100060af40
2019-01-22 23:44:25 - INFO - Success! TODO: update HASS state for entity: `switch.100060af40` to state: on

Hopefully you get to a "Success" message if you press your Sonoff's button, but any output will be valuable for sure 😄

Note: if you add three backticks before/after large log or code blocks, it's formatted with a fixed-width font so much easier to read!

tota-5 commented 5 years ago

Nice! Ill try installing it in my HA and running it (altho i'm suspecting this isnt supposed to be tested in HA yet, as you said I should be running this in python 3 in my environment...)

If im supposed to run this somewhere else, the only thing I got is pycharm, with your project opened and a buch of errors of dependencies showing up and no idea on how to properly configure the project so it can run by itself.

I tried getting home assistant code and hassio code too, and put it all together as a single project, and this solved a lot of the dependencies (as it became obvious that most of the imports were for classes defined in HA or hassio), but i still have dependecy issues, so im just putting ur code in my custom_component folder in HA and hoping for the best, or at least some debug info on how I should be setting this up.

Idk where you are geograpically, im in Brazil, Manaus, -4 UTC, and at the timestamp of this msg, is when im going to be back home tomorrow.

Thank you so much for the help so far! Can i send u some $ help? A patreon or something? I feel like stealing from u lol

tota-5 commented 5 years ago

ok, so I used ur test-sonoff, and got the following log:

Log Details (ERROR)
Tue Jan 22 2019 22:07:59 GMT-0400 (Horário Padrão do Amazonas)

Error during setup of component test_sonoff
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/homeassistant/setup.py", line 148, in _async_setup_component
    component.setup, hass, processed_config)  # type: ignore
AttributeError: module 'custom_components.test_sonoff' has no attribute 'setup'

Log Details (ERROR)
Tue Jan 22 2019 22:11:09 GMT-0400 (Horário Padrão do Amazonas)

Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/homeassistant/helpers/service.py", line 287, in _handle_service_platform_call
    await getattr(entity, func)(**data)
  File "/usr/local/lib/python3.6/concurrent/futures/thread.py", line 56, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/config/custom_components/switch/sonoff_lan_mode.py", line 110, in turn_off
    set_sonoff_state(self._host, "off")
  File "/config/custom_components/switch/sonoff_lan_mode.py", line 35, in set_sonoff_state
    ws = create_connection("ws://" + host + ":8081/")
  File "/usr/local/lib/python3.6/site-packages/websocket/_core.py", line 511, in create_connection
    websock.connect(url, **options)
  File "/usr/local/lib/python3.6/site-packages/websocket/_core.py", line 220, in connect
    options.pop('socket', None))
  File "/usr/local/lib/python3.6/site-packages/websocket/_http.py", line 120, in connect
    sock = _open_socket(addrinfo_list, options.sockopt, options.timeout)
  File "/usr/local/lib/python3.6/site-packages/websocket/_http.py", line 190, in _open_socket
    raise err
  File "/usr/local/lib/python3.6/site-packages/websocket/_http.py", line 170, in _open_socket
    sock.connect(address)
ConnectionRefusedError: [Errno 111] Connection refused

Log Details (ERROR)
Tue Jan 22 2019 22:24:54 GMT-0400 (Horário Padrão do Amazonas)

Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/homeassistant/helpers/service.py", line 287, in _handle_service_platform_call
    await getattr(entity, func)(**data)
  File "/usr/local/lib/python3.6/concurrent/futures/thread.py", line 56, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/config/custom_components/switch/sonoff_lan_mode.py", line 105, in turn_on
    set_sonoff_state(self._host, "on")
  File "/config/custom_components/switch/sonoff_lan_mode.py", line 35, in set_sonoff_state
    ws = create_connection("ws://" + host + ":8081/")
  File "/usr/local/lib/python3.6/site-packages/websocket/_core.py", line 511, in create_connection
    websock.connect(url, **options)
  File "/usr/local/lib/python3.6/site-packages/websocket/_core.py", line 220, in connect
    options.pop('socket', None))
  File "/usr/local/lib/python3.6/site-packages/websocket/_http.py", line 120, in connect
    sock = _open_socket(addrinfo_list, options.sockopt, options.timeout)
  File "/usr/local/lib/python3.6/site-packages/websocket/_http.py", line 190, in _open_socket
    raise err
  File "/usr/local/lib/python3.6/site-packages/websocket/_http.py", line 170, in _open_socket
    sock.connect(address)
ConnectionRefusedError: [Errno 111] Connection refused

Ill keep trying to get a grasp on what to do and finally get to code myself, im in between reading ur code and watching tutorials

tota-5 commented 5 years ago

i think im getting a grasp on how python and HA shinanigans works!

Ive done some coding to resolve the setup issue with aparently success!

Here is what i added to test_sonoff just below the end of the imports, and above the class declaration:


DOMAIN = "test_sonoff"

async def async_setup(hass, config):
    hass.data[DOMAIN] = Sonoff(config)
    return True

and altered the constructor to reflect the new parameter:

    def __init__(self, config):

and no more errors!

But i got this log instead now:

Tue Jan 22 2019 23:05:52 GMT-0400 (Horário Padrão do Amazonas)

WebsocketListener initialising...

followed by

websocket error: [Errno 110] Operation timed out

definitelly seems like progress \o/

beveradb commented 5 years ago

Sorry @ariel-madril, I should have explained better! The test script isn't intended to work from HomeAssistant at all.

I've moved them to a subfolder, and added better explanation and instructions here: non-hass-scripts

Hope those help and you're able to get the test script working and upload a log file! If you have any issues let me know and I'll try and help.

As for me, I'm in Edinburgh, UK (so, GMT), but I work odd hours as I'm a freelancer at the moment.

I appreciate the offer but don't worry, for now, I'm just happy to help get things working for folks. The HomeAssistant setup I've currently got is only possible thanks to many thousands of other open-source contributors, so I'm grateful to be able to give something back! That said, maybe if I manage to get this component to the point where it's a more robust implementation that I'm proud of, I'll consider putting up a donation link 😉

tota-5 commented 5 years ago

ah thank you! That explanation is right on point! I will provide logs latter today!

tota-5 commented 5 years ago

got home! Followed ur superb written tutorial and guess what? Total success!

Here goes the log!

python test_sonoff.py
2019-01-23 22:11:15 - DEBUG - Sonoff class initialising
2019-01-23 22:11:15 - DEBUG - initializing websocket
2019-01-23 22:11:15 - INFO - WebsocketListener initialising, connecting to host: ws://192.168.0.113:8081/
2019-01-23 22:11:15 - DEBUG - attempting to call WebSocketApp run_forever with ping_interval: 145
2019-01-23 22:11:15 - DEBUG - sending user online websocket msg: {"action": "userOnline", "userAgent": "app", "version": 6, "nonce": "004125350002109", "apkVesrion": "1.8", "os": "ios", "at": "at", "apikey": "apikey", "ts": "1548295875", "model": "iPhone10,6", "romVersion": "11.1.2", "sequence": "1548295875745969"}
2019-01-23 22:11:15 - DEBUG - received websocket msg: {"error":0,"apikey":"ae6d40bd-c08f-4928-8116-c575594569bc","sequence":"1548295875745969","deviceid":"1000619812"}
2019-01-23 22:11:15 - DEBUG - received hello from deviceid: 1000619812, no action required
2019-01-23 22:11:15 - DEBUG - received websocket msg: {
"userAgent":"device",
"apikey":"apikey",
"deviceid":"1000619812",
"action":"update",
"params":{
"switch":"on"
}
}
2019-01-23 22:11:15 - INFO - received action: update
2019-01-23 22:11:15 - DEBUG - found update action in websocket update msg
2019-01-23 22:11:15 - DEBUG - found switch/switches in websocket update msg
2019-01-23 22:11:15 - DEBUG - searching for deviceid: [] in known devices 1000619812
2019-01-23 22:11:15 - DEBUG - device not found in known devices, adding
2019-01-23 22:11:29 - DEBUG - received websocket msg: {
"userAgent":"device",
"apikey":"apikey",
"deviceid":"1000619812",
"action":"update",
"params":{
"switch":"off"
}
}
2019-01-23 22:11:29 - INFO - received action: update
2019-01-23 22:11:29 - DEBUG - found update action in websocket update msg
2019-01-23 22:11:29 - DEBUG - found switch/switches in websocket update msg
2019-01-23 22:11:29 - DEBUG - searching for deviceid: [{'userAgent': 'device', 'apikey': 'apikey', 'deviceid': '1000619812', 'action': 'update', 'params': {'switch': 'on'}}] in known devices 1000619812
2019-01-23 22:11:29 - INFO - Success! TODO: update HASS state for entity: `switch.1000619812` to state: off
2019-01-23 22:11:30 - DEBUG - received websocket msg: {
"userAgent":"device",
"apikey":"apikey",
"deviceid":"1000619812",
"action":"update",
"params":{
"switch":"on"
}
}
2019-01-23 22:11:30 - INFO - received action: update
2019-01-23 22:11:30 - DEBUG - found update action in websocket update msg
2019-01-23 22:11:30 - DEBUG - found switch/switches in websocket update msg
2019-01-23 22:11:30 - DEBUG - searching for deviceid: [{'userAgent': 'device', 'apikey': 'apikey', 'deviceid': '1000619812', 'action': 'update', 'params': {'switch': 'off'}}] in known devices 1000619812
2019-01-23 22:11:30 - INFO - Success! TODO: update HASS state for entity: `switch.1000619812` to state: on
2019-01-23 22:11:53 - DEBUG - received websocket msg: {
"userAgent":"device",
"apikey":"apikey",
"deviceid":"1000619812",
"action":"update",
"params":{
"switch":"off"
}
}
2019-01-23 22:11:53 - INFO - received action: update
2019-01-23 22:11:53 - DEBUG - found update action in websocket update msg
2019-01-23 22:11:53 - DEBUG - found switch/switches in websocket update msg
2019-01-23 22:11:53 - DEBUG - searching for deviceid: [{'userAgent': 'device', 'apikey': 'apikey', 'deviceid': '1000619812', 'action': 'update', 'params': {'switch': 'on'}}] in known devices 1000619812
2019-01-23 22:11:53 - INFO - Success! TODO: update HASS state for entity: `switch.1000619812` to state: off
2019-01-23 22:11:58 - DEBUG - received websocket msg: {
"userAgent":"device",
"apikey":"apikey",
"deviceid":"1000619812",
"action":"update",
"params":{
"switch":"on"
}
}
2019-01-23 22:11:58 - INFO - received action: update
2019-01-23 22:11:58 - DEBUG - found update action in websocket update msg
2019-01-23 22:11:58 - DEBUG - found switch/switches in websocket update msg
2019-01-23 22:11:58 - DEBUG - searching for deviceid: [{'userAgent': 'device', 'apikey': 'apikey', 'deviceid': '1000619812', 'action': 'update', 'params': {'switch': 'off'}}] in known devices 1000619812
2019-01-23 22:11:58 - INFO - Success! TODO: update HASS state for entity: `switch.1000619812` to state: on
beveradb commented 5 years ago

Awesome, thank you! I'll get on with turning this test code into a proper HomeAssistant component so it can actually update state, and will mark this resolved once that code is merged - hopefully later today 😄

tota-5 commented 5 years ago

Thank you! I will use ur code to learn more about coding for HA myself. Depending on how good this solves my problem, i might not even flash my sonoffs at all, and focus on debuging the various syncing situations. I want to start coding python, and this seems like an amazing opportunity for me to get some training in me!

beveradb commented 5 years ago

This is now a work in progress, thanks to initial energy from @ariel-madril - see PR #10 above.

I've been chatting to some other HASS devs and I'm really keen to refactor and improve this whole component, add tests, split out the API portion to a library on PyPI etc., but as that will take me quite a bit more time, I'm happy for this to be implemented in a hacky/minimum-functional way for now.

As such, we're probably only a few lines of code away from the update-state branch being functional, so I'll crack on with that once @ariel-madril is online to clarify & merge any progress at his end.

tota-5 commented 5 years ago

I've done some work in my end, mostly trying to learn how to code python, and ended up successfully implementing a connection and listener for each device. Right now i'm struggling with the sonoff devices not connecting to the socket, but i believe that it's just something i must be missing.

Anyway, my code is extremely experimental and dirty, as it's serving me as a learning project.

I will ditch it and test your code as soon as you upload a functional code.

I can help writing error handlers and fall back options for when a device disconnects or unsyncs.

beveradb commented 5 years ago

Just an update, I've now finished implementing a proper asynchronous library to control Sonoff devices in LAN mode: https://github.com/beveradb/pysonofflan

This was the hard part - almost all decent quality HomeAssistant components don't have any core device-specific communication functionality in them; all of that is done in a library which is just imported and used by the hass component.

As such, that's the stage we're at now so tomorrow I'll work on using this library from a hass component, following other "platinum" quality components closely.

In the meantime, it would be appreciated if you could give that library ^ a quick try; it's got a command-line interface so all you should need to do to test it is install it with pip install pysonofflan then run it, giving it your IP. There's further instructions and examples in the README of that repository. Thanks!

Not far away now 😄

peterbuga commented 5 years ago

That is some awesome work you've done there 🚀 👍 ! Looking forward to use this lib to my project one day (soon) 😄

beveradb commented 5 years ago

That's #10 merged now, and I'm pretty happy with the implementation too - it's fully async, and there's very little code in the component itself since everything is in the library.

@ariel-madril, please reinstall this component and test! I've installed it in my production Home Assistant setup and tested with a real Sonoff Basic, and it works perfectly for me.

I'll close this issue once you confirm it's working for you 😄

Bramas commented 5 years ago

Hi and thanks @beveradb. I tried it today and it works with my sonoff basic. It was my first sonoff on my first home assistant installation! I don't know if it is normal but I had to put requirements_dev.txt in the same folder ("custom_components/switch") otherwise the package pysonofflan is not found. But maybe that has nothing to do with it, but after the first restart I got a module not found error.

beveradb commented 5 years ago

Awesome, glad to hear it's working for you @Bramas!

Hmm, the requirements_dev.txt file shouldn't be relevant in any way. The way it's supposed to work is that the first time Home Assistant tries to load a new component, it checks for any requirements defined in this REQUIREMENTS dict here and installs them using pip install.

I'm not sure why it hasn't worked for you first time - if you're able to reproduce at all it would be super helpful if you could share your home assistant log file so I can see the error in context! In my testing on a clean home assistant installation, with nothing in the custom_components folder besides a switch folder containing only sonoff_lan_mode.py, it works fine first time.

The relevant lines in my log file are:

2019-02-04 23:41:02 INFO (MainThread) [homeassistant.loader] Loaded switch from homeassistant.components.switch
2019-02-04 23:41:02 INFO (MainThread) [homeassistant.loader] Loaded switch.sonoff_lan_mode from custom_components.switch.sonoff_lan_mode
2019-02-04 23:41:02 WARNING (MainThread) [homeassistant.loader] You are using a custom component for switch.sonoff_lan_mode which has not been tested by Home Assistant. This component might cause stability problems, be sure to disable it if you do experience issues with Home Assistant.
[...]
2019-02-04 23:41:03 INFO (SyncWorker_5) [homeassistant.util.package] Attempting install of pysonofflan>=0.2.1
2019-02-04 23:41:08 INFO (MainThread) [homeassistant.components.switch] Setting up switch.sonoff_lan_mode
2019-02-04 23:41:08 INFO (MainThread) [homeassistant.setup] Setup of domain switch took 5.3 seconds.
2019-02-04 23:41:08 INFO (MainThread) [homeassistant.bootstrap] Home Assistant initialized in 70.60s
Bramas commented 5 years ago

Hi, I reproduced the error, but it only appears once after the first restart. If I restart again home-assistant, everything works well. It looks like the requirements in REQUIREMENTS are installed after the call of async_setup_platform(...) (see log below).

my setup: ubuntu server 18.04 (in virtualbox in windows 10), docker with home-assistant image. first I launch the docker image to create an account, then add the custom_components/switch/sonoff_lan_mode.py file and the component in the configuration.yaml file and restart homeassistant using the Restart button in the configuration menu, then the error. Here is the log file

2019-02-05 19:31:04 WARNING (MainThread) [homeassistant.loader] You are using a custom component for switch.sonoff_lan_mode which has not been tested by Home Assistant. This component might cause stability problems, be sure to disable it if you do experience issues with Home Assistant.
2019-02-05 19:31:19 ERROR (MainThread) [homeassistant.components.switch] Error while setting up platform sonoff_lan_mode
Traceback (most recent call last):
  File "/usr/src/app/homeassistant/helpers/entity_platform.py", line 128, in _async_setup_platform
    SLOW_SETUP_MAX_WAIT, loop=hass.loop)
  File "/usr/local/lib/python3.6/asyncio/tasks.py", line 358, in wait_for
    return fut.result()
  File "/config/custom_components/switch/sonoff_lan_mode.py", line 34, in async_setup_platform
    async_add_entities([HassSonoffSwitch(hass, host, name)], True)
  File "/config/custom_components/switch/sonoff_lan_mode.py", line 41, in __init__
    from pysonofflan import SonoffSwitch
ModuleNotFoundError: No module named 'pysonofflan'
mattsaxon commented 5 years ago

this has been resolved in the latest version (and in fact quite a few version back)