-
Notifications
You must be signed in to change notification settings - Fork 182
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
Add local dp_x handling based on known product ids #185
Comments
I love the idea @fhempy ! Similar to the community driven Contrib extension for devices, we could add something like a "Products" extension. How would you like to see it work? My first thought... from tinytuya import Products
product_id = 'MShdslm9Uw7Q59nN'
# Look up attributes for product
a = Products.attributes(product_id)
print("Device version = %d - name = %s - type = %s" % (a['version'], a['name'], a['type']))
# Look up data points for product
print("DPS:")
dps = Products.dps(product_id)
for point in dps:
print(" %d = %s - %s", % (dps['id'], dps['name'], dps['type'])
# Advanced Device Connection
d = Products.connect(
product_id,
dev_id='DEVICE_ID_HERE',
address='IP_ADDRESS_HERE',
local_key='LOCAL_KEY_HERE')
d.turn_on()
if d.device() is 'led_switch':
d.set_colour(d.GREEN) I'm sure there is a lot more we could do here. We should also make sure Is this something you would be willing to contribute to help get started? I recommend we start small/simple, perhaps with just the dictionary and some lookup functions (a subset of my "look up" examples above). |
Great to see that you are also interested in this functionality. I would just slightly adapt it:
I think the version shouldn't be part of the mappings, as it depends on the user if a device was updated or not. Therefore I would always detect the version instead of having it in the code.
That's good. I would add:
I would suggest to make the address optional and scan for the IP if it isn't provided. I already had some users where the local IP changed and they forgot to change it in their configuration, therefore I would like to get rid of the IP and just use the dev_id.
I assume you mean that it should work together with the device type extension. I'll try to contribute a first (simple) version. |
All of this makes sense. On the Thanks for raising this idea @fhempy - Looking forward to seeing the PR! ❤️ Simple is gold (I'm a big fan of the MVP approach). |
Unfortunately I'm not really feeling this one. In my experience the DP mapping is only half right with a significant number of device DPs not being in the list, the device not actually using quite a few list DPs, and a handful of DPs that are in both are listed with the wrong scale/step/min/max. If we do add this I think it would be better for the wizard to pull it when retrieving the local keys so we always have the latest version (in case a firmware update adds more) and don't have to maintain or include a massive JSON blob. @jasonacox The auto-IP on connect/init does not use anything from scanner.py, but making the IP detection function in core.py much, much quicker is a relatively minor change. I'll make a PR just for that so we can get that in now while I'm finishing up the scanner.py stuff. |
I love this pivot! @uzlonewolf has a great point. If we include the massive JSON blog in the module, it sort of defeats the whole "Tiny" part of the project. 😜 I looked through the JSON file and it is essentially what we get from a wizard pull (but for products we don't have). I did a spot comparison and the DP mapping is as @uzlonewolf points out, mostly not very helpful. However, I can see some value in data like Questions and thoughts on this pivot:
What else am I missing? |
I say there's no such thing as too much data and would also include |
While working on my test scripts for #188 I realized |
In the PR I already had open I added the storing of that additional data to devices.json. I'm not seeing what a |
Hi,
As I mentioned in the last point I don't use device specific classes. I just provide all DPs to the users. Status DPs are just reported and function DPs are provided as a command on the user interface. As the users don't know what the certain DP is for or which values can be set via commands, I just need the name, type and possible values - I don't need the type of the device. Based on that information I can provide the human readable information to the users. Furthermore I can map DPs which are not provided by tuya iot cloud mappings. I agree that putting the mappings blob to the code is something I don't like either, but I would like to provide the full functionality for users if they know their local key already. As soon as the users have the local key, there shouldn't be a need to connect to the tuya iot cloud as the DPs could be retrieved "locally". So let's focus the discussion on the first step:
|
@fhempy I agree with the theory and would love to see that, however where will the DP mappings come from? The "official" mappings are just straight up wrong, and trying to use them will lead to frustrated users when they do not work. |
I keep thinking about adding this but keep getting stuck on how, exactly, it would work. How would tinytuya get the DPS mappings? If the user provides them then there really isn't much for tinytuya to do besides maybe scaling the set/returned values and enforcing limits when setting; as the user/calling code already has the human-readable names there is no real need for tinytuya to also keep track of them. To use the mostly-incorrect "official" mappings you need the Product Id which means either pulling it from the Cloud (requires internet access and an account) or being directly connected to the local network to receive the broadcasts (will not work if there is a router between you and the device). I have yet to find a way of directly querying a device for the Product Id. Even if you do have the Product Id you still have the issue of what to do with new/unknown devices. In short I don't really understand what it is you want tinytuya to do. Providing the massive blob of mappings fails the "don't need to change anything when a new device is released" test and can easily be done import tinytuya
did = 'efd01234df6510cbd6abcd'
dkey = 'sadfdsafdsafsad'
(dev_ip, dev_ver, dev_info) = tinytuya.find_device(did)
print(dev_info)
if dev_info and 'productKey' in dev_info:
product_id = dev_info['productKey']
dps_mappings = your_dps_lookup( product_id ) # i.e. { 1: {'name': 'Switch 1', 'type': 'bool' } }
else:
product_id = None
dps_mappings = {}
d = tinytuya.OutletDevice( did, dev_ip, dkey, version=float(dev_ver) )
status = d.status()
if status and 'dps' in status:
for dp in status['dps']:
val = status['dps'][dp]
dp = int(dp)
if dp in dps_mappings:
name = dps_mappings[dp]['name']
if 'scale' in dps_mappings[dp] and dps_mappings[dp]['scale']:
val *= dps_mappings[dp]['scale']
else:
name = 'Unknown DPS %d' % dp
print( name, 'is now', val )
# user says "Set 'Switch 1' On":
for dp in dps_mappings:
if dps_mappings[dp]['name'] == 'Switch 1':
d.set_value( dp, True )
break
# user says "Set 'Dimmer 4' to 80%":
for dp in dps_mappings:
if dps_mappings[dp]['name'] == 'Dimmer 4':
d.set_value( dp, 80 )
break Just provide that massive list with your software and refer to it when implementing |
You are right, it can be managed within the codes which use the tinytuya library. That's how I currently implement it. I thought it would make sense that other projects benefit from it as well and therefore tinytuya might be the better place. It would allow us to work together (cross project) on a mapping list which we would maintain together. The only real benefit for tinytuya would be that users don't need to setup the tuya iot project if they know their local key already and the device is already supported in the mappings blob. The best solution would be to have a REST API where users could request mappings and provide new ones via tinytuya. Finally I'm also fine if I continue to maintain the mappings in my project. |
As the "official" mapping list is both ginormous and wrong I do not wish to see it included. I am not opposed to a community-provided/verified list however. Either way, I think it would be a good idea to add a new device type that, when passed mappings obtained from wherever, maps and formats the returned values for you. Say, import tinytuya
dps_data = {
'2' : { 'name': 'mode', 'enum': ['auto', 'cool', 'heat', 'emergencyheat', 'off'] },
'16': { 'name': 'temp_set', 'alt': 'setpoint_c', 'scale': 100 },
}
dev = tinytuya.MappedDevice( 'abcd1234', mapping=dps_data )
# and/or
dev.set_mapping(dps_data)
# equivalent
dev.set.mode = 'heat'
dev.set['mode'] = 2
status = dev.status()
if status and 'changed' in status and 'setpoint_c' in status['changed']:
# setpoint_c changed
# equivalent
print( status['changed']['setpoint_c'] ) # i.e. "24.5"
print( dev.get.setpoint_c ) # i.e. "24.5"
print( dev.get['setpoint_c'] ) # i.e. "24.5" |
there is an endpoint that can provide that information, but in order to get there, it should have login session cookie, const formData = {
"devId": {DEVICE_ID},
"region": {REGION}
};
const headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'csrf-token': "{developerPortalCSRFToken}",
'Cookie': "{developerPortalRegionalCookie}"
}; since it require a manual process of login via browser (with captcha) and extract the cookie (if will be relevant, will post the process), we will need a new endpoint to inject the cookie string, |
Actually I found that changing the Instruction Mode to "DP Instruction" unlocks the full list for the open API. #284 (comment) Finding this actually bumped this "Mapped Device" project to pretty high on my to-do list. Not sure when I'll be able to implement it, hopefully Soon(tm). |
Right, also manage to do that and published it over my repo 2 months ago for HA tuya custom integration, but it's too complex and you need to do that for every device category, with that approach of accessing the dp list is much easier but requires more technical knowledge... will keep investigating of how to extract that without need for dev tools |
Hi,
what do you think about adding known mappings directly to the project as iobroker does?
See https://github.com/Apollon77/ioBroker.tuya/blob/master/lib/schema.json
They use the product id to identify the dp mappings. So you don't need any connection to the cloud if you know your localkey and product id.
I used it in my project as well where I use a combination of tinytuya and localtuya (because of asyncio) code:
https://github.com/fhempy/fhempy/tree/master/FHEM/bindings/python/fhempy/lib/tuya
Would be great to make one mapping list in tinytuya where everybody could contribute.
The text was updated successfully, but these errors were encountered: