BUG ! Computed kWh device cannot be updated with initial svalue (workaround found)

Python and python framework

Moderator: leecollings

Post Reply
willemd
Posts: 661
Joined: Saturday 21 September 2019 17:55
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.1
Location: The Netherlands
Contact:

BUG ! Computed kWh device cannot be updated with initial svalue (workaround found)

Post by willemd »

Below is a small piece of code from a Python Plugin that I am developing using the DomoticzEx framework.
After each piece of code I have pasted the log output. It all seems to work fine except for the final update.
You can see the sValue is not updated onto the device. sValue remains ''" instead of "7;1". Why?
I do not understand why the last update does not work. Someone here does?

The device is a kWh device with the kWh value to be computed from the Watts input (not from device). I have checked the definition of the device and that shows up correctly. According to the Wiki the nValue should be zero and the sValue should be in the format "123;123456" and the second value will be ignored.

Code: Select all

Unit=DEVSLIST[Dev][0]
DeviceID="{:04x}{:04x}".format(self.Hwid,Unit)
Domoticz.Log(responseJson["stats"][Dev])
output is: 2025-06-25 09:22:28.900 Xtend: 7

fieldValue=responseJson["stats"][Dev]
Domoticz.Log(Devices[DeviceID].Units[Unit])
output is: 2025-06-25 09:22:28.900 Xtend: Unit: 43, Name: 'XTEND: HP energy usage', nValue: 7, sValue: '', LastUpdate: 2025-06-25 09:21:17

Devices[DeviceID].Units[Unit].nValue=0
Devices[DeviceID].Units[Unit].sValue=str(fieldValue)+";1" # watts are supplied, kwh are calculated by Domoticz.
Domoticz.Log(Devices[DeviceID].Units[Unit].sValue)
output is: 2025-06-25 09:22:28.900 Xtend: 7;1

Devices[DeviceID].Units[Unit].Update()
Domoticz.Log(Devices[DeviceID].Units[Unit])
output is: 2025-06-25 09:22:28.914 Xtend: Unit: 43, Name: 'XTEND: HP energy usage', nValue: 0, sValue: '', LastUpdate: 2025-06-25 09:22:28
Last edited by willemd on Wednesday 25 June 2025 11:47, edited 3 times in total.
willemd
Posts: 661
Joined: Saturday 21 September 2019 17:55
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.1
Location: The Netherlands
Contact:

Re: Python plugin does not update kWh device. Why?

Post by willemd »

I see an issue 6194 on Github which https://github.com/domoticz/domoticz/issues/6194 also describes the problem, although the description states that the device cannot be created. I can create the device I just cannot populate it with data.

There does not seem to be any action or solution to that issue?
willemd
Posts: 661
Joined: Saturday 21 September 2019 17:55
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.1
Location: The Netherlands
Contact:

Re: Python plugin does not update kWh device. Why?

Post by willemd »

I found that if you put an initial svalue on the device (with sqlite3, directly on the devicestatus table) then after that the update code works correctly.

So it is a bug when the device is created. It should initialize it with an initial svalue.

Or alternatively the update statement should work when there is no initial value.

But how to work around this in a Python plugin?
willemd
Posts: 661
Joined: Saturday 21 September 2019 17:55
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.1
Location: The Netherlands
Contact:

Re: Python plugin does not update kWh device. Why?

Post by willemd »

More info: also updating the device with a JSON statement does not work when there is no initial svalue present.
So the only workaround now is to add a svalue in the devicestatus table first directly in the dbase.

Note there is no problem updating other device types, only the computed kwh device.
willemd
Posts: 661
Joined: Saturday 21 September 2019 17:55
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.1
Location: The Netherlands
Contact:

Re: BUG ! Computed kWh device cannot be updated with initial svalue

Post by willemd »

I think I found where the problem is. It is in line 5371-5397 in the SQLhelper.cpp file.

If the initial svalue does not consists of two elements then it just restores the initial value. So if the initial value is empty (which it always is after the device is created) then the svalue remains empty. Here is the offending code.

Code: Select all

std::vector<std::string> powerAndEnergyBeforeUpdate;
			StringSplit(sValueBeforeUpdate, ";", powerAndEnergyBeforeUpdate);
			if (powerAndEnergyBeforeUpdate.size() == 2)
			{
				//we need to use atof here because some users seem to have a illegal sValue in the database that causes std::stof to crash
				double powerDuringInterval = atof(powerAndEnergyBeforeUpdate[0].c_str());
				double energyUpToInterval = atof(powerAndEnergyBeforeUpdate[1].c_str());
				double energyDuringInterval = powerDuringInterval * intervalSeconds / 3600;
				double energyAfterInterval = energyUpToInterval + energyDuringInterval;
				std::vector<std::string> powerAndEnergyUpdate;
				StringSplit(sValue, ";", powerAndEnergyUpdate);
				if (!powerAndEnergyUpdate.empty())
				{
					const char* powerUpdate = powerAndEnergyUpdate[0].c_str();
                    char sValueUpdate[100];
                    sprintf(sValueUpdate, "%s;%.4f", powerUpdate, energyAfterInterval);
					sValue = sValueUpdate;
				}
				else
				{
                    sValue = sValueBeforeUpdate.c_str();
				}
			}
			else
            {
                sValue = sValueBeforeUpdate.c_str();
            }
willemd
Posts: 661
Joined: Saturday 21 September 2019 17:55
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.1
Location: The Netherlands
Contact:

Re: BUG ! Computed kWh device cannot be updated with initial svalue

Post by willemd »

I found a workaround

1) First I create the kWh device using the plugin with the default "from device" setting (leave the options field empty when creating the device).
2) Immediately after creation, I update the device svalue to "0;0" using the plugin.
3) and then immediately I update the options field to 'EnergyMeterMode': '1' which changes the device to "computed" instead of "from device".

Note in step 3 the update statement needs to be run with the UpdateOptions=True flag like this
Devices[DeviceID].Units[Unit].Update(UpdateOptions=True)

Now it has an initial value and future updates will work.
User avatar
lemassykoi
Posts: 17
Joined: Saturday 11 March 2017 23:51
Target OS: Raspberry Pi / ODroid
Domoticz version: 2025.1
Location: France
Contact:

Re: BUG ! Computed kWh device cannot be updated with initial svalue (workaround found)

Post by lemassykoi »

I had to deal with that same problem:

At first, I'm creating the device (lib Domoticz) with the options, using Typename (cause when using Type and Subtype, it was not working)
Then I init the device with svalue = "0;0"
then updates are ok

Code: Select all

BLUETTI_DEVICE_DEFINITIONS = [
    # Name,                        UnitID, TypeName,        Type, Subtype, DevIDSfx, SwTypeCr, ImgCr, OptsSelector, OptsCreation, JSONKey, Used
    ("Bluetti Device Type",           1,  "Text",             243, 19, "devtype",        0, 0, {}, {}, "device_type",           0),
    ("Bluetti Serial Number",         2,  "Text",             243, 19, "serial",         0, 0, {}, {}, "serial_number",         0),
    ("Bluetti ARM Version",           3,  "Text",             243, 19, "arm",            0, 0, {}, {}, "arm_version",           0),
    ("Bluetti DSP Version",           4,  "Text",             243, 19, "dsp",            0, 0, {}, {}, "dsp_version",           0),
    ("Bluetti Total Battery",         5,  "Percentage",       243, 6,  "totalbatt",      0, 0, {}, {}, "total_battery_percent", 1),
    ("Bluetti DC Input Power",        6,  "kWh",              243, 29, "dcinpow",        0, 0, {}, {"EnergyMeterMode": "1"}, "dc_input_power",          0),
    ("Bluetti AC Input Power",        7,  "kWh",              243, 29, "acinpow",        0, 0, {}, {"EnergyMeterMode": "1"}, "ac_input_power",          1),
    ("Bluetti AC Output Power",       8,  "kWh",              243, 29, "acoutpow",       0, 0, {}, {"EnergyMeterMode": "1"}, "ac_output_power",         1),
    ("Bluetti DC Output Power",       9,  "kWh",              243, 29, "dcoutpow",       0, 0, {}, {"EnergyMeterMode": "1"}, "dc_output_power",         0),
    ("Bluetti Power Generation",      10, "kWh",              243, 29, "pwrgen",         4, 0, {}, {"EnergyMeterMode": "1"}, "power_generation",        0),
    ("Bluetti Internal DC Power",     25, "kWh",              243, 29, "intdcpower",     0, 0, {}, {"EnergyMeterMode": "1"}, "internal_dc_input_power", 0),
    ("Bluetti AC Charging Power",     27, "kWh",              243, 29, "acchargepow",    0, 0, {}, {"EnergyMeterMode": "1"}, "ac_charging_power",       0),
    ("Bluetti AC Output State",       11, "Switch",           244, 73, "acoutstate",     0, 9, {}, {}, "ac_output_on",              1),
    ("Bluetti DC Output State",       12, "Switch",           244, 73, "dcoutstate",     0, 9, {}, {}, "dc_output_on",              1),
    ("Bluetti Grid Charge",           28, "Switch",           244, 73, "gridcharge",     0, 9, {}, {}, "grid_charge_on",            1),
    ("Bluetti Time Control",          29, "Switch",           244, 73, "timecontrol",    0, 9, {}, {}, "time_control_on",           1),
    ("Bluetti Battery Range Start",   60, "Percentage",       243, 6,  "battrangestart", 0, 0, {}, {}, "battery_range_start",       0),
    ("Bluetti Battery Range End",     61, "Percentage",       243, 6,  "battrangeend",   0, 0, {}, {}, "battery_range_end",         0),
    ("Bluetti Time Schedule",         62, "Text",             243, 19, "timeschedule",   0, 0, {}, {}, "time_control_programming",  1),
    ("Bluetti Internal AC Voltage",   14, "Voltage",          243, 8,  "intacvolt",      0, 0, {}, {}, "internal_ac_voltage",       0),
    ("Bluetti Internal AC Frequency", 17, "Custom",           243, 31, "intacfreq",      0, 0, {}, {}, "internal_ac_frequency",     0),
    ("Bluetti AC Input Voltage",      20, "Voltage",          243, 8,  "acinvolt",       0, 0, {}, {}, "ac_input_voltage",          0),
    ("Bluetti Internal Current 3",    21, "Current (Single)", 243, 23, "intcurr3",       0, 0, {}, {}, "internal_current_three",    0),
    ("Bluetti AC Input Frequency",    23, "Custom",           243, 31, "acinfreq",       0, 0, {}, {}, "ac_input_frequency",        0),
    ("Bluetti Internal DC Voltage",   24, "Voltage",          243, 8,  "intdcvolt",      0, 0, {}, {}, "internal_dc_input_voltage", 0),
    ("Bluetti Internal DC Current",   26, "Current (Single)", 243, 23, "intdccurr",      0, 0, {}, {}, "internal_dc_input_current", 0),
    ("Bluetti AC Output Mode",        13, "Selector Switch",  244, 62, "acoutmode",     18, 0, {"LevelActions": "|||||", "LevelNames": "Off|Stop|Inverter Output|Bypass Output C|Bypass Output D|Load Matching", "LevelOffHidden": "false", "SelectorStyle": "1"}, {}, "ac_output_mode", 0),
    ("Bluetti UPS Mode",              30, "Selector Switch",  244, 62, "upsmode",       18, 0, {"LevelActions": "||||", "LevelNames": "Off|Customized|PV Priority|Standard|Time Control", "LevelOffHidden": "false", "SelectorStyle": "1"}, {}, "ups_mode", 1),
]
[...]

Code: Select all

    def create_domoticz_devices(self):
        """Create Domoticz devices"""
        Domoticz.Log("create_domoticz_devices: Starting device check/creation...")
        plugin_key = Parameters["Key"]

        for name, unit_id, type_name, d_type, d_subtype, device_id_suffix, d_switchtype, d_image, create_opts_selector, update_opts_general, json_key, used in BLUETTI_DEVICE_DEFINITIONS:
            full_device_id = f"{plugin_key}_{device_id_suffix}"

            if unit_id not in Devices:
                Domoticz.Log(f"Creating Unit {unit_id} ('{name}')...")
                Domoticz.Device(
                    Name       = str(name),
                    Unit       = int(unit_id),
                    TypeName   = str(type_name),
                    Switchtype = int(d_switchtype),
                    Image      = int(d_image),
                    Options    = dict(update_opts_general),
                    DeviceID   = full_device_id,
                    Used       = int(used)
                ).Create()

            # Apply update options if specified
            if unit_id in Devices and update_opts_general:
                try:
                    current_dev_options = Devices[unit_id].Options if hasattr(Devices[unit_id], 'Options') else {}
                    effective_options = current_dev_options.copy()

                    options_changed = False
                    for opt_key, opt_value in update_opts_general.items():
                        if str(effective_options.get(opt_key)) != str(opt_value):
                            effective_options[opt_key] = opt_value
                            options_changed = True
                    
                    if options_changed: 
                        Devices[unit_id].Update(nValue=Devices[unit_id].nValue, sValue="0;0", Options=effective_options)

                except Exception as e: 
                    Domoticz.Error(f"Error applying update options to {name}: {e}")

            elif unit_id in Devices and create_opts_selector:
                try:
                    Devices[unit_id].Update(nValue=0, sValue="0", Options=create_opts_selector)
                except Exception as e: 
                    Domoticz.Error(f"Error applying selector options to {name}: {e}")

            elif unit_id in Devices and type_name == 'Custom':  # Frequency in Hertz
                try:
                    Devices[unit_id].Update(nValue=0, sValue="50.0", Options={'Custom': '1;Hertz'})
                except Exception as e: 
                    Domoticz.Error(f"Error applying custom options to {name}: {e}")

            self.device_unit_map[json_key] = unit_id
User avatar
waltervl
Posts: 5902
Joined: Monday 28 January 2019 18:48
Target OS: Linux
Domoticz version: 2024.7
Location: NL
Contact:

Re: BUG ! Computed kWh device cannot be updated with initial svalue (workaround found)

Post by waltervl »

just for the record, the bug or behavior is also discussed in this github issue https://github.com/domoticz/domoticz/issues/6194

And just a quote from @pipiche, plugin author of the Zigbee4Domoticz plugin
I'm wondering if the error is not in the (python plugin) code

device1 = Domoticz.Device(Name="EnergyMeterMode1", Unit=1, Type=243, Subtype=29, Switchtype=0, DeviceID="EnergyMeterMode1", Options = {"EnergyMeterMode": 1})

My understanding is that 'EnergyMeterMode' should be a string and not an int, as for the zigbee4domoticz plugin we are doing

Options = {'EnergyMeterMode': '0'} for (from Device) or Options = {'EnergyMeterMode': '1'} for from Compute

and we do not have any issue to report when creating the wdiget
Domoticz running on Udoo X86 (on Ubuntu)
Devices/plugins: ZigbeeforDomoticz (with Xiaomi, Ikea, Tuya devices), Nefit Easy, Midea Airco, Omnik Solar, Goodwe Solar
willemd
Posts: 661
Joined: Saturday 21 September 2019 17:55
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.1
Location: The Netherlands
Contact:

Re: BUG ! Computed kWh device cannot be updated with initial svalue (workaround found)

Post by willemd »

I already used {'EnergyMeterMode': '1'} or {'EnergyMeterMode': '0'} so already defined it as string and still encountered the problem.

As already mentioned, the problem is not in creating the device. Creation works and also the device looks exactly like other "computed" kWh devices (created via the GUI).

The problem is that it cannot be given a new svalue if the initial svalue is empty. Whether you are using a plugin or a JSON, the problem is the same, you cannot assign a svalue if the current svalue is empty.

So therefore, as a workaround, you first have to create the devices as a "from device" kWh meter and make sure svalue is not empty. If then you change the device to "computed" the svalue retains its value, is not empty, and therefore it can be given new values.
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest