jasonacox / tinytuya

Python API for Tuya WiFi smart devices using a direct local area network (LAN) connection or the cloud (TuyaCloud API).
MIT License
872 stars 158 forks source link

Smart plug energy meter DP ID 17 missing #274

Open timmpo opened 1 year ago

timmpo commented 1 year ago

A deltaco smartplug DP ID 17 (Add Electricity) missing but in tuya cloud api its showing

result from Python Dictionary {'devId': 'xxx', 'dps': {'1': False, '9': 0, '18': 0, '19': 0, '20': 2335, '21': 1, '22': 1775, '23': 42125, '24': 126000, '25': 168}}

Result from tuya API

{ "result": [ { "code": "switch_1", "value": false }, { "code": "countdown_1", "value": 0 }, { "code": "add_ele", "value": 101 }, { "code": "cur_current", "value": 0 }, { "code": "cur_power", "value": 0 }, { "code": "cur_voltage", "value": 2335 } ], "success": true, "t": xxx, "tid": "xxx" }

jasonacox commented 1 year ago

Hi @timmpo can you post a link to this plug?

DP ID 17 (Add Electricity)

This datapoint is the amount of energy used over time (e.g. kWh).

To compute energy, you need to perform samples of current power (wattage) over time and determine the "area under the curve" (ie. mathematical integration). So let's say you measure the power p(x), and you do that n times over a period of t hours, you would compute the energy (what DP 17 is trying to give you) using an equation like this:

$$\int_{1}^{n} p(t) dt$$

or

$$\sum (p{1}...p{n}) / t$$

Pratically, if you had a load that ran for 5 hours and you tested it every hour like this:

p(1) = 100W p(2) = 200W p(3) = 300W p(4) = 400W p(5) = 500W

Using the above:

Energy = (100W + 200W + 300W + 400W + 500w) / 5 Energy = 1500W / 5 = 300Wh = 0.3kWh

As you can see, you need to do accumulation of power samples over time to determine the energy. Many "energy" plugs (I own several) do not have a memory feature to record that accumulation so they use the Cloud to record the power (W) samples. The Cloud is then able to perform the math to produce the energy consumption (DP 17). This is why you need to poll the cloud to get DP17.

However, there is the possibility that some smart energy plugs compute this themselves using their onboard memory. It may be that it only emits that reading after a certain interval. In which case, you would likely not get it with a d.status() call.

Try this script to monitor the plug for a while to see if it emits DP 17:

import tinytuya

d = tinytuya.OutletDevice(
       dev_id='DEVICE_ID_HERE',
       address='IP_ADDRESS_HERE',
       local_key='LOCAL_KEY_HERE', 
       version=3.3)

d.set_socketPersistent(True)

print(" > Begin Monitor Loop <")
while(True):
    # See if any data is available
    data = d.receive()
    print('Received Payload: %r' % data)

    # Send keyalive heartbeat
    print(" > Send Heartbeat Ping < ")
    payload = d.generate_payload(tinytuya.HEART_BEAT)
    d.send(payload)
make-all commented 1 year ago

Based on the devices I've seen that implement this, for smart plugs, they accumulate until they have counted 0.1kWh (or 0.01, depending on the scale), and output 1 on the add_ele dp. They then reset and go back to reporting nothing, or 0 on that dp, until they have counted up again.

You could count these pulses, if you are sure you can receive them all without missing any, or as suggested, collect power readings and calculate power usage from them (for example, Home Assistant has a Riemann sum integration helper for doing this).

jasonacox commented 1 year ago

Thanks, @make-all ! I haven't manage to pick up one of these. It seems a bit clumsy but I'm sure there is some use case out there (perhaps the cloud uses this), but I would prefer your approach and sample power over time & compute.

timmpo commented 1 year ago

Hello! Tanx for the info! i I thought the onboard microcontroller calculate the power usage in kwh, but this probably takes place in the cloud. Here in sweden its branded as DELTACO SH-p01E and inside is a 7231N-BK microcontroller.

uzlonewolf commented 1 year ago

The TOPGREENER plugs I picked up appear to work differently. It still needs to be verified, but at this point I feel the operation works like this:

DPS 17 is only reported in .status() requests, it is never transmitted asynchronously. When the switch is Off, DPS 17 holds the last value. When first switched On, if it was off for at least 30 minutes then reset DPS 17 to "1" While the switch is On, update DPS 17 every 30 minutes and reset the internal counter to "1"

Edit: put another way, when it is switched On it starts a 30-minute timer. At the end of those 30 minutes it copies the internal "power used" counter into DPS 17 and resets that internal counter to "1". If the switch is still On it then restarts the timer, otherwise it stops until the switch is next turned On.

backcountrymountains commented 11 months ago

I think I'm having a related issue with my Mini-Split. iot.tuya.com has logs for DP 116 of my device that seem to correspond with power or BTU/h, but the device itself doesn't expose a DP 116 using

detect_available_dps()
{'1': None, '2': None, '3': None, '4': None, '5': None, '18': None, '20': None, '105': None, '110': None, '113': None, '114': None, '119': None, '120': None, '123': None, '126': None, '127': None, '128': None, '129': None, '130': None, '131': None, '132': None, '133': None, '134': None}

or

.status()
Device status: {'devId': '75767832c45bbeda0fa3', 'dps': {'1': True, '2': 800, '3': 23, '4': 'cold', '5': 'mid', '18': 0, '20': 0, '105': 'off', '110': 2228796, '113': '1', '114': '1', '119': '0', '120': 'off', '123': '0010', '126': '0', '127': '0', '128': '0', '129': '1', '130': 26, '131': False, '132': False, '133': '3', '134': '{"t":1689309260,"s":false,"clr":true}'}}

iot.tuya.com shows the following logs for DP 116: image

I tried adding DP 116 using .set_dpsUsed() but that didn't seem to do anything.

.set_dpsUsed({'1': None, '2': None, '3': None, '4': None, '5': None, '18': None, '20': None, '105': None, '110': None, '113': None, '114': None, '116': None, '119': None, '120': None, '123': None, '126': None, '127': None, '128': None, '129': None, '130': None, '131': None, '132': None, '133': None, '134': None})

There is another user that seems to have the same device, but they are able to get data from DP 116 so I'm not sure if we have slightly different models or firmware.

I'm just looking for advice on how to tease out the power readings from the device without using the cloud logging.

Thanks.