-
Notifications
You must be signed in to change notification settings - Fork 191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot connect to Smart Switch #507
Comments
Hi @measwel, Can you post your initialization code? It looks like version is being set as a string ( You do not need to disconnect the device in the SmartLife app, simply closing the app is fine. As for multiple connections, this is going to depend on what the device supports; some devices can handle 2-4 simultaneous connections while others only allow 1. |
I read device from device.json based on stored uuids of devices I am interested in.
I will try to float it. |
It works 👍 Thank you.
A few words about what I am building. I am trying to make an app for darkroom work. I plan to make the app open source as it should be quite useful for people who like to develop their own black and white photos in the darkroom. |
Nice project @measwel ! Keep us posted. 😁 Thanks @uzlonewolf somewhere in my "don't have time" TODO list I had planned to explore how to type-safe our parameters. There's never enough time but we could use this issue to flag that. |
I thought we were casting the version to a float, but looking at the code it seems that's only done when passed into |
Would indeed be helpful for those who read the device params from devices.json.
PS Would be nice to include the device name in the message too, but it's not part of the handle object. I would probably have to dig into devices.json to fetch it. |
3 sleepless nights later I have a prototype to show. :) https://github.com/measwel/darkroom Would very much appreciate your feedback. |
Nice job @measwel ! |
I can't get error handling quite right. How to check if a device is online? The less I freeze up the interface, the better. Getting the exposure time right, means the devices must respond swiftly. So I currently execute the action (like switching on the enlarger) and afterwards check the device status. Why do I check it? So in case a device went offline, I can tell the user, throw an exception and try to reconnect. It would be better if I could check the device status in a non blocking way. Either with a callback or in a thread. As far as I know .status() does not have a callback one could use, so I will try to run it in a thread. |
So I made this threaded routine to check the status of a device after using it. It seems to work, but I do not really know if this makes sense or not :)
|
Here is a script to scan through a list of devices and detect which are online or offline. Notice the additional connection settings in the constructor (OutletDevice): import json
import os
import tinytuya
# Load all device details from devices.json
print('\nLoad devices.json')
devices = []
if os.path.exists('devices.json'):
with open('devices.json') as json_file:
devices = json.load(json_file)
else:
print('devices.json not found')
# Or optionally, Set your own device details here:
devices = [
{
"name": "Switch",
"id": "xxxxxxxx",
"ip": "x.x.x.x",
"key": "xxxxxxxxxxxxxxxx",
"version": "3.3"
},
{
"name": "Light",
"id": "xxxxxxxx",
"ip": "x.x.x.x",
"key": "xxxxxxxxxxxxxxxx",
"version": "3.1"
},
{
"name": "Fan",
"id": "xxxxxxxx",
"ip": "x.x.x.x",
"key": "xxxxxxxxxxxxxxxx",
"version": "3.3"
},
]
# Loop through devices and check to see which are online
print('\nCheck Devices')
for device in devices:
if not device['id'] or not device['ip'] or not device['key']:
continue
# Connect to device
d = tinytuya.OutletDevice(dev_id=device['id'],
address=device['ip'],
local_key=device['key'],
version=device['version'],
connection_timeout=1,
connection_retry_limit=1,
connection_retry_delay=1,
)
# Check status of device
data = d.status()
if "Error" in data:
print(f"{device['name']} - OFFLINE")
else:
print(f"{device['name']} - ONLINE ({data})") |
Interesting. It is doing the same thing I am currently doing with 2 differences.
|
I would propose:
The benefit is, that checking the status runs in its own thread this way and does not block the main program. When the thread finishes, data can be read out normally. |
I only do this when checking the status. For other functions I do want the tuya code to run synchronous, so the events happen in the correct sequence. Imagine I have 10 darkroom lamps. I send commands to switch them all off then switch on the enlarger. I do not want checking the status of those 10 lamps to block the program and interfere with switching the enlarger off again at the right time. |
I always first run some function on the device, then check the status of that device. Why? Because some functions will return an Error when executed, but others will not. For instance : d.set_status(False) <-- Turn off the smart outlet of the enlarger. This does return an error when the outlet is offline. l.turn_off() <-- Turn off rgb led lamp. This does not return an Error when the lamp is offline. turning the lamp off, does not seem to return an error code, even when the device is offline. So I need to get the status to find out if a lamp has malfunctioned. |
Well done @measwel One note, I think you could replace data = d.turn_off()
if "Error" in data:
print(f"{device['name']} - OFFLINE ({data})")
else:
print(f"{device['name']} - ONLINE ({data})") Also, as a note, without adding the
As you mention, this is less of an issue if you are threading the calls and not blocking the main loop. |
Hi @jasonacox, thanks for your suggestions. I think I will stick with using .status() as that works every time. Yes, I set other connection settings to speed things up. I cannot finish the part that would do the automatic exposure time calculation as I do not have a light intensity meter yet. Perhaps you know someone who does and could maybe help out? |
Something like this? I haven't used this but there appear to be several options out there. I don't know if this would work for your use case. |
Thank you @jasonacox. That is exactly the model I was looking at. I ordered it. It has usb power and a sensitivity scale from 0 to 1000 lumen, which should give enough resolution I hope. What I do not know, is whether the scale is linear. Will 2 times as much light produce a two times bigger sensor value? I guess I will find out. It should be easy to test, as each F-stop on my enlarger lens increases / decreases the light output by 2. |
I bought 5 new RGB LED bulbs and a new smart outlet switch. I paired the devices. They work in the smartlife app. I pulled their data from the cloud with the wizard. But for some reason the scan does not find the new devices on the network. Polling local devices... What could be wrong? Could it be that the new devices connect over a different port? I would gladly help testing / debugging to get this problem resolved. Maybe the new devices use yet another version of the API to communicate? |
Hi @measwel , sure that is all possible. Can you share a link to thee bulbs so we can get some to test? Also, can you provide the debug dump? |
Debug scan output: DEBUG:Listening for Tuya devices on UDP ports 6666, 6667 and 7000 Scan Complete! Found 1 devices. It seems to find just 1 device, which is my older smart plug switch. |
Interesting, both of those inks are 404 for me, but may be region locked. What is the exact name of the product I can search for? As to the devices, please confirm they are just WiFi and not using a gateway (e.g. Zigbee)? Also, try to have the scanner do a force scan |
Updated the links. Will do the forced scan now. |
Parsed args: Namespace(debug=False, command='scan', debug2=True, max_time=None, force=[[]], no_broadcasts=False, nocolor=False, yes=False, device_file='devices.json', snapshot_file='snapshot.json') DEBUG:Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun 6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32 TinyTuya (Tuya device scanner) [1.14.1] [Loaded devices.json - 19 devices] Scanning on UDP ports 6666 and 6667 and 7000 for devices for 18 seconds... DEBUG:Listening for Tuya devices on UDP ports 6666, 6667 and 7000
DEBUG:Received valid UDP packet: {'ip': '192.168.51.246', 'gwId': 'bfadddf28e43521d4c7man', 'active': 2, 'ablilty': 0, 'encrypt': True, 'productKey': 'keyjup78v54myhan', 'version': '3.3'} DEBUG:Received valid UDP packet: {'ip': '192.168.51.246', 'gwId': 'bfadddf28e43521d4c7man', 'active': 2, 'ablilty': 0, 'encrypt': True, 'productKey': 'keyjup78v54myhan', 'version': '3.3'} Scan Complete! Found 1 devices.
DEBUG:Scan complete with 1 devices found |
The device does not appear on the same network as your host. Do you have multiple WiFi networks set up? |
My main router is giving out IPs via DHCP and provides WiFi downstairs. Then I have a WiFi capable switch upstairs which just acts as a switch, providing WiFi upstairs. It has DHCP switched off. The two smart outlets (one called 'enlarger', the other 'Dark Switch') are currently both connected to the WiFi upstairs. But for some reason, the scan finds one of them and not the other. |
Maybe this will help too. Old switch: "model": "BSD-BPEQ16" (works) Old RGB LED: "model": "50-LM-025", "product_name": "E27 RGB CCT" |
The computer you are running |
Ok, so in the debug only I would try: And script with each IP (you mentioned you did get the ID and Key for these via Wizard): d = tinytuya.OutletDevice(
dev_id=DEVICEID,
address="192.168.51.198,
local_key=DEVICEKEY,
version=3.3)
data = d.status()
print(data) |
192.168.51.246 is the old outlet switch. The new outlet and the 5 new RGB Leds do not show up in the scan. |
I would try direct access to see what happens: d = tinytuya.OutletDevice(
dev_id=DEVICEID,
address="192.168.51.198,
local_key=DEVICEKEY,
version=3.3)
data = d.status()
print(data) |
I will try. In the mean time, maybe this link works? |
I tried both with BulbDevice and OutletDevice. I am not sure if I got the IP / deviceID / key combo right. I tried for all IPs. It all ended in: DEBUG:status() received data={'Error': 'Check device key or version', 'Err': '914', 'Payload': None} |
What version did you see from the wizard? Try changing the version in the script from 3.3 to 3.4 and 3.5. |
@jasonacox, are you US or Europe based? I am thinking about reordering as one of the RGB LEDs I got is broken (only the blue led works). Ali tells me to send the whole order back for a refund which is nonsense. I get a super deal on these devices and for 9 bucks I can get 2 more LEDs and 1 more switch. What if I let them be shipped to an address designated by you? Then you could keep one LED and switch, try them out and send one LED to me, so I can have 5 working ones? |
Update. I am able to connect to one of the new RGB LEDs using version 3.5 : db = tinytuya.BulbDevice(dev_id=device_id, address=i, local_key=device_key, version=3.5, connection_timeout=1, connection_retry_limit=1, connection_retry_delay=0) {'dps': {'20': True, '21': 'colour', '22': 10, '23': 269, '24': '006803e803e8', '25': '000e0d0000000000000000c80000', '26': 0, '34': False}} I am also able to connect to the new smart plug, also by setting version to 3.5 and manually setting IP and key. {'dps': {'1': True, '9': 0, '18': 0, '19': 0, '20': 2383, '21': 1, '22': 572, '23': 29257, '24': 15834, '25': 2630, '26': 0, '38': 'memory', '39': 'relay', '40': False, '41': '', '42': '', '43': '', '51': False}} The scan does not find the devices however. Maybe these new devices broadcast on a different port? I did notice this error when doing a forced scan:
|
I received the light sensor today. The scan finds it and I am able to get a reading from it. But the new bulbs and switch are not found by the scan. Here are direct links to the devices which are not found by the scanner. I hope these links work? https://www.aliexpress.us/item/3256805811828814.html https://www.aliexpress.us/item/3256805544389239.html For the time being, I checked the new IPs on my network and made a small script to find working combinations of IP and device key. Then I had the script add the IP and Version in devices.json. This way all my devices work. The only problem is, that I was not able to find them with the tinytuya scanner. |
Thanks @measwel - those links worked! I was able to order. I'll let you know what happens. |
That's great. I am sure we will figure it out. |
The force scan was broken in the last update, #511 fixes it. You are the 2nd person to report a v3.5 device not broadcasting. I hope this is not a new trend... |
I played with the light intensity sensor today. Some suprising results. Good: it works 😄. Strange: with a opal light bulb the measurement is linear. Changing 1 stop on the lens halves the measured lux value. I also tried a LED bulb. In this case the measured values did not quite get halved, but it was close enough to be practical I guess. Interesting: a cold white light gives more measured lux than a warm white light at the same brightness setting. Bad: the sensitivity of the sensor is on the low side. The scale goes from 0 to 1000. With an average setting on my enlarger (20 x 20 cm print, F5.6) I am getting a reading of 16 lux. Making a big print or closing down the lens to F22 will bring the measured value to 0 lux. Conclusion; it is sensible to use the strongest bulb feasible in the enlarger head. I will try with the strongest LED bulb I can find. This should do it: https://www.ebay.de/itm/155860485532 4000K to get good contrast, opal white and a whopping 3500 lumen. |
An alternative - but maybe stupid - scanning procedure would be: Find existing IPs in devices.json. This is basically how I figured out the IP and version of the v3.5 devices which did not show up on the scan. The only difference being, that I did not ping to find the new IPs. I just exported them from my router. Come to think of it... Probably something very similar is done by the forced scan. :) |
This is the code I used:
As said, the list of new IPs to try I got from my router. But I think one could try to find them with a ping on the same subnet. As all my device names ment for the Darkroom start with "Dark" I can skip the others. Also, I noticed it made no difference whether I used outlet or bulb for the connection test. |
Yes, the force-scan does something similar: it waits a few seconds to look for broadcast packets, and then starts trying every IP address it did not hear a broadcast from. It goes one step further and uses non-blocking sockets and select() to interrogate 10 devices in parallel every main loop tick (shakes out to around 100 simultaneous requests). Once a connection is established it starts trying every device version and local key combination (minus the keys it already found) until it gets a match. |
OutletDevice is going to be a little quicker as the BulbDevice makes a connection and calls status() to try and figure out what bulb type it is as soon as the BulbDevice() object is created. Personally I prefer to use tinytuya.Device() when the device type is not known as I feel it makes it a bit more obvious when reading the code that the device type is not known yet. |
I'm not too hopeful, but, if you run this in one terminal: import tinytuya
import socket
import time
bcast = b'{"from":"app","ip":"192.168.51.1"}'
bcast_port = 7000
bcast_to = '255.255.255.255'
bcast_idx = 0
bcast_cmd = 0x25
bcast_retcode = None
bcast_msg = tinytuya.TuyaMessage( bcast_idx, bcast_cmd, bcast_retcode, bcast, 0, True, tinytuya.PREFIX_6699_VALUE, True )
bcast_packet = tinytuya.pack_message( bcast_msg, hmac_key=tinytuya.udpkey )
bsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # UDP
bsock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
while True:
print("broadcast encrypted=%r" % bcast_packet.hex() )
bsock.sendto( bcast_packet, (bcast_to, bcast_port) )
bsock.sendto( bcast_packet, (bcast_to, bcast_port) )
time.sleep(5) Does |
Okay, the Terminal was firing broadcast messages such as: In the other Terminal I did a scan: Unknown v3.4 Device Product ID = tgkr1bwom0jcn3cx [Valid Broadcast]: Scan Complete! Found 1 devices. The bulbs and the outlet switch were not found. What it did find, (192.168.51.15) is the light intensity sensor. But that thing was also found by a regular scan before. |
Yeah, I figured that wasn't going to work, but thought it was worth a shot. I ordered those AliExpress devices and they should get here today so hopefully I'll be able to figure out what's going on. |
My devices came in and I made some progress. The problem with these new devices is 2-fold: they do not broadcast at all unless they receive a "from: app" broadcast on port 7000, and they broadcast to port 7000. Receiving their broadcasts is a minor change to the scanner as it already listens on port 7000 for apps, but sending a broadcast to get the devices to start broadcasting is turning out to be a bit trickier than I thought. |
Hey @uzlonewolf, interesting results so far. I hold my thumbs for you to find a good way to get them to broadcast. Maybe a useful hint, maybe not: I noticed they do return a ping, so maybe one could use that to filter what IPs to try on the network. |
There's no point to pinging them, just attempting a TCP connection with a short time-out does the same thing while also making it so the 2nd step is ready to go should the connection succeed. It currently creates parallel connections to about 50 IP addresses per second, so attempting connections to an entire /24 only takes ~8 seconds (5.12 seconds to open connections plus 3 seconds for the time-out if there's no response from the last IP). I'll probably be going out of town early next week so I may or may not be able to get sending broadcasts implemented this weekend. It's pretty easy to do on machines which only have 1 IP address, but there's no good way to get a list of IPs in python on multi-interface machines. |
Yeah, got that. Enjoy your time outside of town. |
Good day,
The device shows up in the scan. The local key has been fetched with the wizard.
enlarger Product ID = keyjup78v54myhan [Valid Broadcast]:
Address = 192.168.51.246 Device ID = bfadddf28e43521d4c7man (len:22) Local Key = xxxxxxxxx Version = 3.3 Type = default, MAC = 10:5a:17:dc:fd:32
Status: {'1': True, '9': 0, '18': 0, '19': 0, '20': 2346, '21': 1, '22': 610, '23': 30696, '24': 17327, '25': 2410, '26': 0, '38': 'memory', '39': False, '40': 'relay', '41': False, '42': '', '43': '', '44': ''}
I read through all the issues concerning 901 connection errors, but not found a solution.
DEBUG:ERROR Network Error: Unable to Connect - 901 - payload: null
DEBUG:status() received data={'Error': 'Network Error: Unable to Connect', 'Err': '901', 'Payload': None}
I have 2 clues.
1 : the core.py throws an error:
File "...\AppData\Local\Programs\Python\Python312\Lib\site-packages\tinytuya\core.py", line 1009, in _get_socket
if self.version >= 3.4:
^^^^^^^^^^^^^^^^^^^
TypeError: '>=' not supported between instances of 'str' and 'float'
2 : maybe other active connections are blocking access to the device?
I have a smart life app on my phone which shows the device. Disconnecting the device in the app does not work. When I disconnect without wiping data, the switch still loses its wifi settings. I have to repair it in the app to get it to show on the wifi network again.
Just closing the smart life app on the phone also does not help. Could it be, because other home members also have that app on their phone and are possibly making a connection? If so, how should I solve that? Should I remove the device from all the smart life apps?
Thank you.
So I do not know how to make sure no other active connections are present.
The text was updated successfully, but these errors were encountered: