Page 1 of 1

DZvents & Python scripts

Posted: Saturday 03 October 2020 18:33
by ricorico94
Hi,

I installed a X725 UPS on my raspberry Pi and I wanted to monitor in Domoticz the voltage of the battery. The X725 provides some python scripts to retrieve measures using I2C tools (it does import smbus library in python).
I could modify the python script from vendor to update device value in domoticz:

Code: Select all

#!/usr/bin/env python
import struct
import smbus
import urllib

def readVoltage(bus):
     address = 0x36
     read = bus.read_word_data(address, 2)
     swapped = struct.unpack("<H", struct.pack(">H", read))[0]
     voltage = swapped * 1.25 /1000/16
     return voltage

bus = smbus.SMBus(1) # 0 = /dev/i2c-0 (port I2C0), 1 = /dev/i2c-1 (port I2C1)
VOLTAGE_BATTERY = readVoltage(bus)
domoticz_V = "9999"     # IDX for virtual sensor for voltage
httpresponse = urllib.urlopen("http://127.0.0.1:8080/json.htm?type=command&param=udevice&idx=" + str(domoticz_V) + "&nvalue=0&svalue=" + str(float(VOLTAGE_BATTERY)))
That script works and I created a DZvents script, triggered by time, to call this python script every 3 minutes (I think each minute would be too frequent):

Code: Select all

return {
	on = {
		timer = {
			'every 3 minutes',				-- causes the script to be called every 3 minutes
				}
	},
	execute = function(domoticz, timer)
		domoticz.log('Timer UPS_Battery event was triggered by ' .. timer.trigger, domoticz.LOG_INFO)
		domoticz.utils.osExecute("/usr/bin/python /home/pi/domoticz/scripts/python/BatteryX725.py")
	end
}
It seems working and I preferred this way rather than using a CRON tab, because if I want to reinstall my domoticz, I don't like having to recreate CRON tabs.. But my approach is still not totally satisfactory, because:
- I don't use embedded Events module of domoticz for the python script..
- I use a url call to update domoticz
- my python script needs to be also updated in case I modify the IDX of device..
- and also I've the feeling that I use more CPU capability than I should.

So is there a better way to handle my need ?
Like using this python smbus library or equivalent directly in dzvents ?
or like dzvents retrieving directly the voltage value from the python script without the script having to call the URL ?
or even maybe using the Python script embedded in domoticz Events ? (but I couldn't find musch documentation on tht one, and I didn't understand how to trigger every X minutes and how to really update the device value..)

Thanks for your hints !
Ricorico94

Re: DZvents & Python scripts

Posted: Saturday 03 October 2020 19:30
by waaren
ricorico94 wrote: Saturday 03 October 2020 18:33 But my approach is still not totally satisfactory, because:
- I use a url call to update domoticz
So is there a better way to handle my need ?
Don't know if it is better but to get rid of the url call you could change the python script to

Code: Select all

#!/usr/bin/env python
import struct
import smbus

def readVoltage(bus):
     address = 0x36
     read = bus.read_word_data(address, 2)
     swapped = struct.unpack("<H", struct.pack(">H", read))[0]
     voltage = swapped * 1.25 /1000/16
     return voltage

print (readVoltage(bus))
And the dzVents to

Code: Select all

return
{
    on =
    {
        timer =
        {
            'every 3 minutes',                -- causes the script to be called every 3 minutes
        },
    },

    logging =
    {
        level = domoticz.LOG_DEBUG,
        marker = getVoltage,
    },

    execute = function(dz)

        local voltSensor = dz.devices(9999) -- or use name of the sensor between quotes if you prefer that

        local function osCommand(cmd)
            dz.log('Executing Command: ' .. cmd,dz.LOG_DEBUG)

            local fileHandle = assert(io.popen(cmd .. ' 2>&1 || echo ::ERROR::', 'r'))
            local commandOutput = assert(fileHandle:read('*a'))
            local returnTable = {fileHandle:close()}

            if commandOutput:find '::ERROR::' then     -- something went wrong
                dz.log('Error ==>> ' .. tostring(commandOutput:match('^(.*)%s+::ERROR::') or ' ... but no error message ' ) ,dz.LOG_ERROR)
            else -- all is fine!!
                dz.log('ReturnCode: ' .. returnTable[3] .. '\ncommandOutput:\n' .. commandOutput, dz.LOG_DEBUG)
            end

            return commandOutput,returnTable[3] -- rc[3] contains returnCode
        end

        local voltage = osCommand('/usr/bin/python /home/pi/domoticz/scripts/python/BatteryX725.py')
        voltSensor.updateVoltage(voltage)
    end
}
BTW the osCommand is implemented as native dzVents function in dz.utils.osCommand() in version 3.0.13 (domoticz 2020.2 build 12394)

Re: DZvents & Python scripts  [Solved]

Posted: Sunday 04 October 2020 9:10
by ricorico94
Hi Waaren,

Thanks a lot for your suggestion which looks interesting, at least to minimize maintenance or customization of the python script.
The DZvents script seems more complex, but most f it is due to error/debug management which is also a good thing.

br,
Ricorico94