Reading XML from IPX800 Topic is solved

Moderator: leecollings

Post Reply
User avatar
laco
Posts: 86
Joined: Tuesday 30 October 2018 12:57
Target OS: NAS (Synology & others)
Domoticz version: 2021.1
Location: Slovensko
Contact:

Reading XML from IPX800

Post by laco »

Hello.
I am reading xml from IPX800 http://192.168.1.125/status.xml

Code: Select all

<response>
<led0>0</led0>
<led1>0</led1>
<led2>0</led2>
<led3>0</led3>
<led4>0</led4>
<led5>0</led5>
<led6>0</led6>
<led7>0</led7>
<btn0>up</btn0>
<btn1>up</btn1>
<btn2>up</btn2>
<btn3>dn</btn3>
<an1>0</an1>
<an2>0</an2>
<time0>19:16:16</time0>
</response>
I created LUA script to read:

Code: Select all

commandArray = {}

function XML_Capture(cmd,flatten)
   local f = assert(io.popen(cmd, 'r'))
   local s = assert(f:read('*a'))
   f:close()
   if flatten  then
      s = string.gsub(s, '^%s+', '')
     s = string.gsub(s, '%s+$', '')
      s = string.gsub(s, '[\n\r]+', ' ')
   end
   return s
end

debug = true

-- DOMOTICZ IDX
IDX1=117 --motion sensor 1
IDX2=118 --motion sensor 2




Device_IPX800 = "192.168.1.125"

if debug == true then
        print("Reading values from: 'http://"..Device_IPX800.."/status.xml'")
end

-- Read the XML data from the device IPX800

XML_string=XML_Capture("curl -s 'http://"..Device_IPX800.."/status.xml'",1)

valid = string.find(XML_string, "<response>")    -- check we are looking in the right place

    if debug == true then
        print(XML_string)
    end
   

 
return commandArray
I see in the log that it writes it right.

LOG:

Code: Select all

2019-06-05 19:59:26.808 Status: LUA: Reading values from: 'http://192.168.1.125/status.xml'
2019-06-05 19:59:26.858 Status: LUA: <response> <led0>0</led0> <led1>0</led1> <led2>0</led2> <led3>0</led3> <led4>0</led4> <led5>0</led5> <led6>0</led6> <led7>0</led7> <btn0>up</btn0> <btn1>up</btn1> <btn2>up</btn2> <btn3>dn</btn3> <an1>0</an1> <an2>0</an2> <time0>19:26:51</time0> </response>

I need to write the motion sensor value to IDX1:
  <btn3> dn </btn3> switch open
<btn3> up </btn3> switch closed

Can anyone help me? Well thank you.
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Reading XML from IPX800

Post by waaren »

laco wrote: Wednesday 05 June 2019 20:01 I am reading xml
I need to write the motion sensor value to IDX1:
  <btn3> dn </btn3> switch open
<btn3> up </btn3> switch closed
Can anyone help me?
This should do it. Please feel free to ask clarification when not clear.

Code: Select all

commandArray = {}

    local Device_IPX800 =  '192.168.1.125'
    local motionSensor1 = 'motion sensor 1' -- change to name of your motion sensor 1
    local debug = false
    
    local function XML_Capture(cmd, flatten) -- cmd required, flatten optional
        local f = assert(io.popen(cmd, 'r')) -- open file for reading
        local s = assert(f:read('*a')) -- read complete file into string
        f:close() -- close file
        
        if flatten then  -- when flatten is not equal to false or nil then the file will be 'flattened'
            s = string.gsub(s, '[\n\r]+', ' ') -- replace all (multiple) CR/LF from string s with a space
          
        else -- action not set so defaults to converting xml to table
            lines = {}
            local validXML = false
            for row in s:gmatch('[^\r\n]+') do -- read one line from string s into row 
                debug = ( debug and print(row) ) or debug  -- print line when debug is set
                validXML = validXML or ( row == '<response>' )  -- did we find the string that makes this xml valid ?
                lines[row:match('<(%w+)>') or 'nil'] = row:match('<.->(.-)<') -- xml tag will be the key and content will be value
            end
            debug = ( debug and print('XML Valid? : ' .. tostring(validXML))) or debug -- print line when debug is set
            lines = ( validXML and lines )  or {} -- nullify lines when no valid response
        end
        return lines or s -- return table or flattened string
    end
    
    debug = ( debug and print("Reading values from: 'http://" .. Device_IPX800 .. "/status.xml'") ) or debug -- print line when debug is set
    
    -- Read the XML data from the device IPX800 into a table
        -- Please note that a curl command can potentially blocks the entire domoticz event system 
        -- So advise is to add maxTime parm (-m 5 ) for n seconds. (or use dzVents where aSync method domoticz.openURL can be used)
    local xmlTable = XML_Capture("curl -m 5 -s 'http://" .. Device_IPX800 .. "/status.xml'") 
    -- local xmlTable = XML_Capture('cat /usr/local/domotica/xml.in') -- test file 
    
    local action = 'On'   -- default value; will also be used when xml was not valid !
    if xmlTable.btn3 == 'up' then action = 'Off' end 
    
    commandArray[motionSensor1] = action
 
return commandArray
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
User avatar
laco
Posts: 86
Joined: Tuesday 30 October 2018 12:57
Target OS: NAS (Synology & others)
Domoticz version: 2021.1
Location: Slovensko
Contact:

Re: Reading XML from IPX800

Post by laco »

Thank you very much, it works perfectly.

Please, you can do a script to read the temperature of an1 and an2
and write it into a virtual thermometer in domoticz?

Temperature reading every 5 minutes
Rounding to 1 decimal

The formula for calculating the temperature is an1 * 0.323

Virtual temp1 = IDX59
Virtual temp2 = IDX60

The script can be lua or dzvents

well thank you
User avatar
laco
Posts: 86
Joined: Tuesday 30 October 2018 12:57
Target OS: NAS (Synology & others)
Domoticz version: 2021.1
Location: Slovensko
Contact:

Re: Reading XML from IPX800

Post by laco »

Everything works, but still sending off status. Creates a large log file.
Spoiler: show
2019-09-19 15:14:53 Off
2019-09-19 15:14:52 Off
2019-09-19 15:14:52 Off
2019-09-19 15:14:52 Off
2019-09-19 15:14:52 Off
2019-09-19 15:14:52 Off
2019-09-19 15:14:52 Off
2019-09-19 15:14:52 Off
2019-09-19 15:14:52 Off
2019-09-19 15:14:52 Off
2019-09-19 15:14:52 Off
2019-09-19 15:14:52 Off
2019-09-19 15:14:52 Off
2019-09-19 15:14:52 Off
2019-09-19 15:14:52 Off
2019-09-19 15:14:52 Off
2019-09-19 15:14:52 Off
2019-09-19 15:14:52 Off
2019-09-19 15:14:52 Off
2019-09-19 15:14:51 Off
2019-09-19 15:14:51 Off
2019-09-19 15:14:51 Off
2019-09-19 15:14:51 Off
2019-09-19 15:14:51 Off
2019-09-19 15:14:51 Off
You will need to modify the script.
After sending the command on to send only 1x off
Last edited by laco on Thursday 19 September 2019 15:25, edited 1 time in total.
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Reading XML from IPX800

Post by waaren »

laco wrote: Thursday 19 September 2019 15:15 Everything works, but still sending off status. Creates a large log file.
It looks like you saved it as device or all type triggered event. You should save it as a time triggered event.
When I find the time I will look into this and your earlier question and convert it into a dzVents script.
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Reading XML from IPX800

Post by waaren »

laco wrote: Thursday 19 September 2019 12:52 Please, you can do a script to read the temperature of an1 and an2
and write it into a virtual thermometer in domoticz?
Can you try this dzVents script ?
Handles both the temperatures and the motion detector.

Code: Select all

local scriptVersion = '0.201909191600'
local scriptVar  =  'IPX800_' .. scriptVersion

--[[ 
this dzVents script is used to collect data from IPX800 
It uses a openURL call and interprets the returned XML code. 

Before activating the script:
    please read the GETTING STARTED section of the dzVents wiki. 
 ]]--

return
{
    on = 
    { 
        timer = { 'every 5 minutes' }, -- is this frequent enough for the motion detection part? 
        httpResponses = { scriptVar }, 
    },

    logging =   
    {
        level = domoticz.LOG_DEBUG,
        marker = scriptVar,
    },
    
   execute = function(dz, item)
        local IPX800IP =  '192.168.1.125'
        
        local an1Temperature = dz.devices(59) 
        local an2Temperature = dz.devices(60)
        local motionDetector = dz.devices('Pohyb fitness')
        
        local temperatureFactor = 0.323

        local function getIPX800XML()
            local url = 'http://' .. IPX800IP .. '/status.xml'
            dz.openURL({ url = url, callback = scriptVar })
        end
        
        local function processXML(xmlData)
            local validator = '<response>'
            if not(xmlData:find(validator)) then return end

            local usedFields = { "btn3", "an1", "an2" }
            local tupels = {}

            for _, key in ipairs(usedFields) do
                for tag in  xmlData:gmatch('<' .. key .. '%s?[^>]->') do
                    local _, beginValueString = xmlData:find(tag)
                    local _, endValueString = xmlData:find('<', beginValueString)
                    local value = xmlData:sub(beginValueString + 1, endValueString - 1)
                    tag = tag:gsub('[<>]','')
                    dz.log("Value of " .. tag ..  ' ==> '.. value ,dz.LOG_FORCE)
                    tupels[tag] = value
                end
            end
            return tupels
        end

        local function updateTemperatureSensor(device, value)
            if device and value then device.updateTemperature(dz.utils.round((value * temperatureFactor),1 )) end
        end

        local function updateMotionDetector(device, activate)
            if device and activate then device.switchOn().checkFirst()
            elseif device then device.switchOff().checkFirst()
            end
        end
        
        local function errorReport(message)
            dz.log(message, dz.LOG_ERROR)
            dz.log('Received: ' .. tostring(item.data),dz.LOG_FORCE)
        end
        
       -- main 
        if item.isTimer or item.isDevice then
            getIPX800XML()
        elseif item.ok then -- statusCode == 2xx
            local result = processXML(item.data)
            if result then 
                updateMotionDetector(motionDetector, result.btn3 == 'dn' )
                updateTemperatureSensor(an1Temperature, result.an1) 
                updateTemperatureSensor(an2Temperature, result.an2)
            else
                errorReport('Could not get valid XML from ' .. IPX800IP)
            end
        else
            errorReport('Could not get (good) data from ' .. IPX800IP)
        end
    end
}
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
User avatar
laco
Posts: 86
Joined: Tuesday 30 October 2018 12:57
Target OS: NAS (Synology & others)
Domoticz version: 2021.1
Location: Slovensko
Contact:

Re: Reading XML from IPX800

Post by laco »

Analog temperature sensors work great.
You can easily set the shooting time.
Only digital readers may need to be separately scripted to send the status only if there is an intrusion of the object.

Thank you great job.
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest