philips air purifier

All kinds of 'OS' scripts

Moderator: leecollings

Post Reply
martijnvdijk
Posts: 8
Joined: Sunday 13 October 2013 20:35
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: Netherlands
Contact:

philips air purifier

Post by martijnvdijk »

Hello,

I recently bought a philips air purifier that i like to connect to my domoticz in combination with my Voltcraft CO-20 it should give some insight on the climate in my working room.

I can across a command line app (https://github.com/rgerganov/py-air-control) that lets me read all the setting.
On the prompt i can now use the follow command: airctrl --ipaddr *.*.*.* --protocol coap
and the result is:
Spoiler: show

Code: Select all

pi@pi:~ $ airctrl --ipaddr *.*.*.* --protocol coap
[name]                        Name: ********
[type]                        Type: AC2729
[modelid]                     ModelId: AC2729/10
[swversion]                   Version: 0.2.1
[om]                          Fan speed: 2
[pwr]                         Power: ON
[cl]                          Child lock: False
[aqil]                        Light brightness: 100
[uil]                         Buttons light: ON
[mode]                        Mode: allergen
[func]                        Function: Purification & Humidification
[rhset]                       Target humidity: 50
[rh]                          Humidity: 58
[temp]                        Temperature: 22
[pm25]                        PM25: 3
[iaql]                        Allergen index: 5
[aqit]                        Air quality notification threshold: 7
[ddp]                         Used index: IAI
[rddp]                        rddp: 0
[wl]                          Water level: 100
[fltt1]                       HEPA filter type: NanoProtect Filter Series 3 (FY2422)
[fltt2]                       Active carbon filter type: NanoProtect Filter AC (FY2420)
[fltsts0]                     Pre-filter and Wick: clean in 338 hours
[fltsts1]                     HEPA filter: replace in 4778 hours
[fltsts2]                     Active carbon filter: replace in 4778 hours
[wicksts]                     Wick filter: replace in 4778 hours
[ota]                         Over the air updates: ck
[Runtime]                     Runtime: 16.21 hours
[WifiVersion]                 WifiVersion: [email protected]
[ProductId]                   ProductId: ***********
[DeviceId]                    DeviceId: ************
[StatusType]                  StatusType: localcontrol
[ConnectType]                 ConnectType: Localcontrol
Can someone help me with getting the data inside domoticz?

I also found a phyton script (https://github.com/bobzomer/domoticz_pyaircontrol) but can't get it to work, and i don't know if it is finished.
But looking at the command prompt output i have the idea that running a cronjob and then import the data is the easier way.

======

At this moment i get the following messages from the phyton script.

2020-10-04 22:43:09.345 Error: Expected: myVar = Domoticz.Device(Name="myDevice", Unit=0, TypeName="", Type=0, Subtype=0, Switchtype=0, Image=0, Options={}, Used=1)
2020-10-04 22:43:09.345 Error: (lucht) 'CDevice_init' failed 'TypeError':''Custom' is an invalid keyword argument for this function'.
2020-10-04 22:43:09.345 Error: Device creation failed, Device object is not associated with a plugin.
2020-10-04 22:43:09.345 Error: (lucht) 'onStart' failed 'ValueError':'not enough values to unpack (expected 5, got 4)'.
2020-10-04 22:43:09.345 Error: (lucht) ----> Line 157 in '/home/pi/domoticz/plugins/domoticz_pyaircontrol/plugin.py', function onStart
2020-10-04 22:43:09.345 Error: (lucht) ----> Line 108 in '/home/pi/domoticz/plugins/domoticz_pyaircontrol/plugin.py', function onStart
2020-10-04 22:43:09.345 Error: (lucht) ----> Line 79 in '/home/pi/domoticz/plugins/domoticz_pyaircontrol/plugin.py', function checkDevices
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: philips air purifier

Post by waaren »

martijnvdijk wrote: Tuesday 06 October 2020 11:59 On the prompt i can now use the follow command: airctrl --ipaddr *.*.*.* --protocol coap

Can someone help me with getting the data inside domoticz?
Happy to help. What information do you want and do you want it in a virtual sensor or uservariable?
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
martijnvdijk
Posts: 8
Joined: Sunday 13 October 2013 20:35
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: Netherlands
Contact:

Re: philips air purifier

Post by martijnvdijk »

Hello Waaren,

I think most values are interesting as a virtual sensor, so i can see / plot the changes over time.
When i look at the returned values from the command a lot of them are interesting variables to monitor.

When i understand it correct:
virtual sensors are presented at the dashboard with graphs etc. and the values can be used as trigger for a notification or eq a blocky "script".
A user variable i only used for further us in scripts etc.
martijnvdijk
Posts: 8
Joined: Sunday 13 October 2013 20:35
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: Netherlands
Contact:

Re: philips air purifier

Post by martijnvdijk »

the values that i really like to monitor are bold below:
[name] Name: ********
[type] Type: AC2729
[modelid] ModelId: AC2729/10
[swversion] Version: 0.2.1
[om] Fan speed: 2
[pwr] Power: ON
[cl] Child lock: False
[aqil] Light brightness: 100
[uil] Buttons light: ON
[mode] Mode: allergen
[func] Function: Purification & Humidification
[rhset] Target humidity: 50
[rh] Humidity: 58
[temp] Temperature: 22
[pm25] PM25: 3
[iaql] Allergen index: 5
[aqit] Air quality notification threshold: 7
[ddp] Used index: IAI
[rddp] rddp: 0
[wl] Water level: 100
[fltt1] HEPA filter type: NanoProtect Filter Series 3 (FY2422)
[fltt2] Active carbon filter type: NanoProtect Filter AC (FY2420)
[fltsts0] Pre-filter and Wick: clean in 338 hours
[fltsts1] HEPA filter: replace in 4778 hours
[fltsts2] Active carbon filter: replace in 4778 hours
[wicksts] Wick filter: replace in 4778 hours
[ota] Over the air updates: ck
[Runtime] Runtime: 16.21 hours
[WifiVersion] WifiVersion: [email protected]
[ProductId] ProductId: ***********
[DeviceId] DeviceId: ************
[StatusType] StatusType: localcontrol
[ConnectType] ConnectType: Localcontrol


Data like [mode] Mode: allergen, [func] Function: Purification & Humidification could be use full but more difficult to monitor over time so not so relevant.
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: philips air purifier

Post by waaren »

martijnvdijk wrote: Tuesday 06 October 2020 15:39 the values that i really like to monitor are bold below:
Not all sensors done yet but first version to test in below dzVents script:

Domoticz sensors implemented
[rh] Humidity: 58 // tempHum sensor
[temp] Temperature: 22 // tempHum sensor
[fltsts0] Pre-filter and Wick: clean in 338 hours // Alert device
[fltsts2] Active carbon filter: replace in 4778 hours // text device
[wicksts] Wick filter: replace in 4778 hours // text device

What type of sensors do you envisage for these values?
[om] Fan speed: 2
[pwr] Power: ON
[pm25] PM25: 3
[iaql] Allergen index: 5
[rddp] rddp: 0
[wl] Water level: 100
[fltsts1] HEPA filter: replace in 4778 hours
[Runtime] Runtime: 16.21 hours

________________________________________________________________________________________________________________
When not yet familiar with dzVents please start with reading Get started Before implementing (~ 5 minutes). Special attention please for "In Domoticz go to Setup > Settings > Other and in the section EventSystem make sure the checkbox 'dzVents enabled' is checked. Also make sure that in the Security section in the settings you allow 127.0.0.1 to not need a password. dzVents uses that port to send certain commands to Domoticz. Finally make sure you have set your current location in Setup > Settings > System > Location, otherwise there is no way to determine nighttime/daytime state."
________________________________________________________________________________________________________________

Code: Select all

--[[

        Purpose of the script is to get data from a Philips purifier

        history:
        20201006 Start coding
        20201006 Initial release on forum


        key / values available:
        -----------------------
        Vents: > Active carbon filter type: NanoProtect F   ilter AC (FY2420)
        WifiVersion: [email protected]
        DeviceId: ************
        Active carbon filter: replace in 4778 hours
        Child lock: False
        Runtime: 16.21 hours
        StatusType: localcontrol
        Version: 0.2.1
        Water level: 100
        Target humidity: 50
        Power: ON
        ModelId: AC2729/10
        Function: Purification & Humidification
        Wick filter: replace in 4778 hours
        Temperature: 22
        Light brightness: 100
        Allergen index: 5
        Used index: IAI
        Air quality notification threshold: 7
        Type: AC2729
        rddp: 0
        HEPA filter: replace in 4778 hours
        PM25: 3
        Mode: allergen
        Humidity: 58
        Name: ********
        ProductId: ***********
        Over the air updates: ck
        HEPA filter type: NanoProtect Filter Series 3 (FY   2422)
        Pre-filter and Wick: clean in 338 hours
        ConnectType: Localcontrol
        Fan speed: 2
        Buttons light: ON

--]]

return
{
    on =
    {
        timer =
        {
            'every minute', -- Once per minute. Change to the frequency you need
        },
        devices =
        {
            'purifyTrigger', -- just for test. Can be ignored
        },
    },

    logging =
    {
        level = domoticz.LOG_DEBUG, -- change to domoticz.LOG_ERROR when all ok.
        marker = 'Purifier',
    },

    execute = function(dz, item)
        -- devices
        local tempHum = dz.devices('Purifier temperature') -- define as virtual temperature / Humidity sensor
        local status = dz.devices('Purifier status') -- define as virtual text sensor
        local alert = dz.devices('Purifier alert') -- define as virtual alert device

        -- os Command
        local getPurifyDataCommand = 'sudo airctrl --ipaddr *.*.*.* --protocol coap'
        -- local getPurifyDataCommand = 'sudo cat /usr/local/domotica/data/purifier' -- for test (file contains std output)

        -- functions
        local function osCommand(cmd)
            local file = io.popen(cmd)
            local output = file:read('*all')
            local rc = { file:close() }
            return output, rc[3]
        end

        local function data2Table(str)
            keyTable = {}
            for line in str:gmatch("([^\n]*)\n?") do
               local key = line:match("%b]:"):sub(3,-2)
               local value = line:match(":%s(.*)")
               local value = tonumber(value) or value
               keyTable[key] = value
            end
            return keyTable
        end

        local function humidityStatus(temperature, humidity)
            if humidity <= 30 then return dz.HUM_DRY
            elseif humidity >= 70 then return dz.HUM_WET
            elseif  humidity >= 35 and
                    humidity <= 65 and
                    temperature >= 22 and
                    temperature <= 26 then return dz.HUM_COMFORTABLE
            else return dz.HUM_NORMAL end
        end

        local function alertLevel(hours)
            hours = tonumber(hours) or -1
            if hours < 48  then return dz.ALERTLEVEL_RED end
            if hours < 96  then return dz.ALERTLEVEL_YELLOW end
            if hours < 144 then return dz.ALERTLEVEL_ORANGE end
            return dz.ALERTLEVEL_GREEN
        end

        local function updateDevices(t)
            status.updateText('status: ' .. t.StatusType .. '\n' .. 'Function: '  .. t.Function .. '\n' ..'RunTime: '  .. t.Runtime .. '\n' ..
                'Carbon filter: '  .. t['Active carbon filter'] .. '\n' ..'Wick filter: '  .. t['Wick filter'] )
            tempHum.updateTempHum(t.Temperature, t.Humidity, humidityStatus(t.Temperature, t.Humidity))
            alert.updateAlertSensor(alertLevel(t['Pre-filter and Wick']:match('%d+')), t['Pre-filter and Wick'])
        end

        -- main 
        local purifyData, rc = osCommand(getPurifyDataCommand)
        if rc ~= 0 or #purifyData < 500 then
            dz.log('Problem retrieving data from Purifier', dz.LOG_ERROR)
        else
            updateDevices(data2Table(purifyData))
        end
    end
}
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
martijnvdijk
Posts: 8
Joined: Sunday 13 October 2013 20:35
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: Netherlands
Contact:

Re: philips air purifier

Post by martijnvdijk »

i have just made the first try to implement the script and now get the following message:
Purifier: An error occurred when calling event handler AirPurifier
2020-10-06 19:31:01.331 Error: dzVents: Error: (3.0.2) Purifier: ...moticz/scripts/dzVents/generated_scripts/AirPurifier.lua:117: attempt to concatenate a nil value (field 'Wick filter')
martijnvdijk
Posts: 8
Joined: Sunday 13 October 2013 20:35
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: Netherlands
Contact:

Re: philips air purifier

Post by martijnvdijk »

possible sensor types:

[om] Fan speed: 2
[pwr] Power: ON = Switch (on/off)
[pm25] PM25: 3 = custom sensor (value ranges from 1 until 12)
[iaql] Allergen index: 5 = custom sensor (value ranges from 1 until 12)
[rddp] rddp: 0 = i'm still trying to figure out what this might me but probably a alert or text
[wl] Water level: 100 = percentages ( waterlevel going down from 100 till 0)
[fltsts1] HEPA filter: replace in 4778 hours = might be text or a alert, all the filters are counters that go down until cleaning or replacement
[Runtime] Runtime: 16.21 hours =custom sensor (operational time of the device)
martijnvdijk
Posts: 8
Joined: Sunday 13 October 2013 20:35
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: Netherlands
Contact:

Re: philips air purifier

Post by martijnvdijk »

I have been trying to find the problem and i think there is a problem with reading the result from the command.
first i have removed line 117 then i got a new error: AirPurifier.lua:98: attempt to compare nil with number

then i just made a test file with some data: $airctrl --ipaddr 192.168.178.* --protocol coap >/tmp/testpurifier
and then made a small change in the code

Code: Select all

-- local getPurifyDataCommand = 'sudo airctrl --ipaddr 192.168.178.* --protocol coap'
        local getPurifyDataCommand = 'sudo cat /tmp/testpurifier' -- for test (file contains std output)
Inside the testpurifier file is the following data (the product id and device id i have replaced by ******:

Code: Select all

[name]                        Name: werkkamer martijn
[type]                        Type: AC2729
[modelid]                     ModelId: AC2729/10
[swversion]                   Version: 0.2.1
[om]                          Fan speed: 2
[pwr]                         Power: ON
[cl]                          Child lock: False
[aqil]                        Light brightness: 100
[uil]                         Buttons light: ON
[mode]                        Mode: allergen
[func]                        Function: Purification & Humidification
[rhset]                       Target humidity: 50
[rh]                          Humidity: 58
[temp]                        Temperature: 20
[pm25]                        PM25: 2
[iaql]                        Allergen index: 4
[aqit]                        Air quality notification threshold: 7
[ddp]                         Used index: IAI
[rddp]                        rddp: 0
[wl]                          Water level: 100
[fltt1]                       HEPA filter type: NanoProtect Filter Series 3 (FY2422)
[fltt2]                       Active carbon filter type: NanoProtect Filter AC (FY2420)
[fltsts0]                     Pre-filter and Wick: clean in 329 hours
[fltsts1]                     HEPA filter: replace in 4769 hours
[fltsts2]                     Active carbon filter: replace in 4769 hours
[wicksts]                     Wick filter: replace in 4769 hours
[ota]                         Over the air updates: ck
[Runtime]                     Runtime: 0.79 hours
[WifiVersion]                 WifiVersion: [email protected]
[ProductId]                   ProductId: ******
[DeviceId]                    DeviceId: ******
[StatusType]                  StatusType: localcontrol
[ConnectType]                 ConnectType: Localcontrol
This doesn't work, but when i replace the values from the values from first post it does work.
so the formatting looks like the problem
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: philips air purifier

Post by waaren »

martijnvdijk wrote: Tuesday 06 October 2020 19:44 possible sensor types:
Send you a PM.
Let's take it to private mail and publish it here in the public part until finished
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: philips air purifier

Post by waaren »

waaren wrote: Tuesday 06 October 2020 21:33 Let's take it to private mail and publish it here in the public part until finished
As promised:

Code: Select all

--[[
        Purpose of the script is to get data from a Philips purifier and update the corresponding domoticz devices
        Prerequisite is an installed and working air-control.

        This can be found here https://github.com/rgerganov/py-air-control

        Thx to @martijnvdijk for initial idea, testing and feedback

        history:
        20201006 waaren            Start coding
        20201007 waaren            Add extra loglines and some devices
        20201007 waaren            Sort filtertimes for alertDevice
        20201007 waaren            Add notification/email to timely order and/or clean filter(s)
        20201010 waaren            Executing airctrl in background for increased resilience
        20201012 waaren            Add extra debug logging
        20201014 martijnvdijk      Intercept and convert to number when fanspeed value is reported as string
        20201014 waaren            Add cumulatedRuntime function
        20201015 waaren            Public release on domoticz forum

        key / values available:
        -----------------------
        Active carbon filter type: String
        WifiVersion: string
        DeviceId: string
        Active carbon filter: string with hours until replacement as integer
        Child lock: Boolean
        Runtime: string with hours as float
        StatusType: string
        Version: string
        Water level: integer
        Target humidity: integer
        Power: string (ON/OFF)
        ModelId: string
        Function: string
        Wick filter: string with hours until replacement as integer
        Temperature: integer
        Light brightness: integer
        Allergen index: integer range
        Used index: string
        Air quality notification threshold: integer range
        Type: string
        rddp: integer
        HEPA filter: string with hours until replacement as integer
        PM25: integer range
        Mode: string
        Humidity: integer
        Name: string
        ProductId: string
        Over the air updates: string
        HEPA filter type: string
        Pre-filter and Wick: string with hours until cleaning as integer
        ConnectType: string
        Fan speed: integer range
        Buttons light: string ON/OFF

        implemented
        -----------
        Fan speed:            Custom sensor
        Power:                Switch
        Humidity:             tempHum
        Temperature:          tempHum
        PM25:                 Custom sensor
        Allergen index:       Custom sensor
        rddp:0                Text Sensor
        Water level:          Percentage
        Pre-filter and Wick:  Custom Sensor + Alert + Notification + Email
        HEPA filter:          Custom Sensor + Alert + Notification + Email
        Active carbon filter: Custom Sensor + Alert + Notification + Email
        Wick filter:          Custom Sensor + Alert + Notification + Email
        Runtime:              Custom Sensor

-]]

scriptVar = 'Purifier'

return
{
    on =
    {
        timer =
        {
            'every 5 minutes', -- Once per 5 minutes. Change to the frequency you need
        },

        customEvents =
        {
            scriptVar .. '*',
        },
    },

    data =
    {
        repeats =
        {
            initial = 0,
        },
        lastNotification =
        {
            initial = 0,
        },
        lastRuntime =
        {
            initial = 0,
        },
        cumulatedRuntime =
        {
            initial = 0,
        },
    },

    logging =
    {
        level = domoticz.LOG_DEBUG, -- change to domoticz.LOG_ERROR when all ok.
        marker = scriptVar,
    },

    execute = function(dz, item)
        ------------------------------------------------------------------- Your settings below this line
        -- devices
        local tempHum = dz.devices('Purifier temperature')            -- define as virtual temperature / Humidity sensor
        local status = dz.devices('Purifier status')                  -- define as virtual text sensor
        local alert = dz.devices('Purifier alert')                    -- define as virtual alert device
        local power = dz.devices('Purifier power')                    -- define as virtual switch
        local water = dz.devices('Purifier waterlevel')               -- define as percentage
        local airQuality = dz.devices('Purifier airquality')          -- define as custom sensor  (use µg/m3 as X-level)
        local allergen = dz.devices('Purifier allergen index')        -- define as custom sensor (use space as X-level)
        local runtime = dz.devices('Purifier runtime')                -- define as custom sensor (hours)
        local fanspeed = dz.devices('Purifier fanspeed')              -- define as custom sensor (use space as X-level)
        local HEPAFilter = dz.devices('Purifier HEPA filter')         -- define as custom sensor (hours)
        local carbonFilter = dz.devices('Purifier carbon filter')     -- define as custom sensor (hours)
        local wickFilter = dz.devices('Purifier wick filter')         -- define as custom sensor (hours)
        local preFilter = dz.devices('Purifier pre filter')           -- define as custom sensor (hours)

        -- (temp) files
        local purifyData = '/tmp/purifyData'

        -- IP address
        local ipAddress = 'xxx.xxx.xxx.xxx'

        local myNotificationTable =
        {
             -- table with one or more notification systems.
             -- uncomment the notification systems that you want to be used
             -- Can be one or more of

             -- dz.NSS_FIREBASE_CLOUD_MESSAGING,
             dz.NSS_PUSHOVER,
             -- dz.NSS_HTTP,
             -- dz.NSS_KODI,
             -- dz.NSS_LOGITECH_MEDIASERVER,
             -- dz.NSS_NMA,
             -- dz.NSS_PROWL,
             -- dz.NSS_PUSHALOT,
             -- dz.NSS_PUSHBULLET,
             -- dz.NSS_PUSHOVER,
             -- dz.NSS_PUSHSAFER,
             dz.NSS_TELEGRAM,
        }

        -- various settings
        local maxRepeats = 5                             -- Try max this number of times before giving up
        local notificationTimeWindow = '09:00-23:00'     -- no messages outside this window
        local notifyBeforeHour = 120                     -- Hours before required filter cleaning / replacement to receive notification
        local emailNotification = '[email protected]'     -- remove this line if you do not want an Email notification
        ----
        ------------------------------------------------------------------- No changes required below this line

        -- os Commands
        local createPurifyDataCommand = 'sudo airctrl --ipaddr ' .. ipAddress  .. ' --protocol coap > ' .. purifyData  .. ' &' -- & ==>> force command to background
        local getPurifyDataCommand = 'sudo cat ' .. purifyData
        local killProcessCommand = 'sudo pkill -ec airctrl' -- kill process and display processes killed + count of killed processes
        local cleanup = 'sudo rm ' .. purifyData

        -- dz.emitStrings
        local startOver = scriptVar .. '_startOver'
        local collectData = scriptVar .. '_collectData'

        -- functions
        local function dumper(data, name)
            if _G.logLevel == dz.LOG_DEBUG then
                if type(data) ~= 'table' then
                    dz.log((name or 'string Dumper') .. ': ' ..  dz.utils._.str(data):gsub('\n','; ') ,dz.LOG_DEBUG)
                else
                    dz.log((name or 'table Dumper') .. ': ___________',dz.LOG_DEBUG)
                    dz.utils.dumpTable(data)
                end
            end
        end

        local function osCommand(cmd) -- osCommmand is also a native function ( dz.utils.osCommand ) in domoticz >= V2020.2 build 12394 (dzVents 3.0.13)
            local file = io.popen(cmd)
            local output = file:read('*all')
            local rc = { file:close() }
            dumper(output, 'from osCommand' )
            return output, rc[3]
        end

        local function data2Table(str)
            keyTable = {}
            for line in str:gmatch('([^\n]*)\n?') do
               local key = line:match('%b]:'):sub(3,-2):match('^%s*(.*)'):gsub('%W','_') -- %w is all letters and digits so %W is everything else
               local value = line:match(':%s(.*)')
               local value = tonumber(value) or value
               keyTable[key] = value
               if line:find('%d hours') and line:find('ilter') then
                    keyTable[key .. '_Counter'] = tonumber(keyTable[key]:match("%d+"))
               end
               if value == 'turbo' then keyTable[key] = 4 end
               if value == 'silent' then keyTable[key] = 0.5 end
            end
            dumper(keyTable, 'from data2Table')
            return keyTable
        end

        local function humidityStatus(temperature, humidity)
            if humidity <= 30 then return dz.HUM_DRY
            elseif humidity >= 70 then return dz.HUM_WET
            elseif  humidity >= 35 and
                    humidity <= 65 and
                    temperature >= 22 and
                    temperature <= 26 then return dz.HUM_COMFORTABLE
            else return dz.HUM_NORMAL end
        end

        local function alertLevel(hours)
            hours = tonumber(hours) or -1
            if hours < ( notifyBeforeHour / 4 ) then return dz.ALERTLEVEL_RED end
            if hours < ( notifyBeforeHour / 2 ) then return dz.ALERTLEVEL_YELLOW end
            if hours < notifyBeforeHour  then return dz.ALERTLEVEL_ORANGE end
            return dz.ALERTLEVEL_GREEN
        end

        local function notification(filters)
             if dz.time.matchesRule('at ' .. notificationTimeWindow) and dz.data.lastNotification <  os.time() - 72000  then -- at least 20 hours after previous notification
                dz.notify('Purifier', 'filter(s) need cleaning or replacement:\n' .. filters, dz.PRIORITY_NORMAL,dz.SOUND_DEFAULT, '' , myNotificationTable)
                dz.data.lastNotification = os.time()
                if emailNotification then
                    dz.email('Purifier', 'filter(s) need cleaning or replacement:\n' .. filters, emailNotification)
                end
             end
        end

        local function sortTable(t, order)
            -- collect the keys
            local keys = {}
            for k in pairs(t) do keys[#keys+1] = k end

            -- if order function given, sort by it by passing the table and keys a, b,
            -- otherwise just sort the keys
            if order then
                table.sort(keys, function(a,b) return order(t, a, b) end)
            else
                table.sort(keys)
            end

            -- return the iterator function
            local i = 0
            return function()
                i = i + 1
                if keys[i] then
                    return keys[i], t[keys[i] ]
                end
            end
        end

        local function combineAlerts(t)
            local alertText = ''
            local notificationText = ''
            local filters = {}
            local maxLevel = 0

            -- select records and determine maxLevel
            for key, hours in pairs(t) do
                if key:find('_Counter') then
                    dz.log(key .. ': ' .. hours,dz.LOG_DEBUG)
                    maxLevel = math.max(maxLevel, alertLevel(hours))
                    filters[key] = tonumber(hours)
                end
            end

            -- sort records and create String
            for key, hours in sortTable(filters, function(t ,a ,b ) return t[b] > t[a] end) do
                alertText = alertText .. key:gsub('_Counter',''):gsub('_',' ') .. ': ' .. hours .. '\n'
                if hours < notifyBeforeHour then
                    notificationText = notificationText .. key:gsub('_Counter',''):gsub('_',' ') .. ' within ' .. hours .. ' hours\n'
                end
            end

            return maxLevel, alertText, ( notificationText ~= '' and notificationText )
        end

        local function cumulatedRuntime(str)
            local hours = tonumber(str:match("%.*(%d+%.*%d*)%.*")) -- isolate number from runtime string

            if hours < dz.data.lastRuntime then -- hours reset to 0 ?!
                dz.data.cumulatedRuntime = dz.data.cumulatedRuntime + dz.data.lastRuntime
            end

            dz.data.lastRuntime = hours
            return ( hours + dz.data.cumulatedRuntime ) .. ' hours'
        end

        local function processReturn(t)
            -- Text sensor
            status.updateText('status: ' .. t.StatusType .. '\n' .. 'HEPA filter: '  .. t.HEPA_filter.. '\n' ..'rddp: '  .. t.rddp .. '\n' ..
                'Carbon filter: '  .. t.Active_carbon_filter.. '\n' ..'Wick filter: '  ..  t.Wick_filter)

            -- Temperature / Humidity
            tempHum.updateTempHum(t.Temperature, t.Humidity, humidityStatus(t.Temperature, t.Humidity))

            --Alert sensor
            local maxLevel, alertText, notificationText = combineAlerts(t)
            alert.updateAlertSensor(maxLevel, alertText)

            --Percentage
            water.updatePercentage(t.Water_level)

            -- On/Off switch
            if t.Power == 'ON' then
                power.switchOn().checkFirst()
            else
                power.switchOff().checkFirst()
            end

            --Custom sensors
            airQuality.updateCustomSensor(t.PM25)
            allergen.updateCustomSensor(t.Allergen_index)
            fanspeed.updateCustomSensor(t.Fan_speed)
            HEPAFilter.updateCustomSensor(t.HEPA_filter_Counter)
            carbonFilter.updateCustomSensor(t.Active_carbon_filter_Counter)
            wickFilter.updateCustomSensor(t.Wick_filter_Counter)
            preFilter.updateCustomSensor(t.Pre_filter_and_Wick_Counter)

            -- "managed" Custom sensors
            runtime.updateCustomSensor(cumulatedRuntime(t.Runtime))

            --Notification / email
            if notificationText then
                notification(notificationText)
            end
        end

        -- main
        if item.isDevice or item.isTimer or item.trigger == startOver then
            osCommand(createPurifyDataCommand)  -- (re)start the sequence
            dz.emitEvent(collectData).afterSec(10)
        elseif item.trigger == collectData then
            if dz.utils.fileExists(purifyData) then
                local purifyDataString, rc = osCommand(getPurifyDataCommand)
                if rc ~= 0 or #purifyDataString < 500 then
                    dz.log('Unexpected problem retrieving data from Purifier. Giving up now', dz.LOG_ERROR)
                    dz.log('Content of purify datafile: '  ..  purifyDataString .. '; ReturnCode is: ' .. rc , dz.LOG_DEBUG)
                else
                    processReturn(data2Table(purifyDataString))
                    dz.data.repeats = 0
                    osCommand(cleanup)
                end
            else
                osCommand(killProcessCommand) -- Process did not return data so assume it hangs
                dz.data.repeats = dz.data.repeats + 1
                if dz.data.repeats >= maxRepeats then
                    dz.notify('Purifier', 'Tried ' .. dz.data.repeats .. ' times. Giving up now.', dz.PRIORITY_HIGH,dz.SOUND_DEFAULT, '' , myNotificationTable)
                else
                    dz.log('Unexpected problem retrieving data from Purifier. Retrying', dz.LOG_ERROR)
                    dz.emitEvent(startOver).afterSec(10 + 60 * dz.data.repeats) -- increasing delay
                end
            end
        end
    end
}
Have Fun!
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
devguy
Posts: 7
Joined: Saturday 17 November 2018 9:58
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: philips air purifier

Post by devguy »

The posted scripts here are wrappers around py-air-control. It's a nice tool but not dealing the right way with the COAP protocol that is being used by my Philips device (AC3829/10). If you read out the sensor values once in a while there is no issue, but don't use this for continuously polling like Domoticz. The fundamental wrong way that py-air-control reads out the sensor values make the network stack of the device crash after a certain time. This can be solved by disconnecting the device from the power...

The device expects clients that are interested in updates to subscribe using the COAP protocol. The device keeps pushing updated values to the client without any additional request. This is something py-air-control doesn't support.

I uploaded my solution on GitHub. It's a plugin for Domoticz. It's only tested with the AC3829/10 device. You can find it on https://github.com/roldoe/domoticz-philips-air
martijnvdijk
Posts: 8
Joined: Sunday 13 October 2013 20:35
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: Netherlands
Contact:

Re: philips air purifier

Post by martijnvdijk »

I have try'ed the plugin but when i starts up i get some error messages, i have send a pm about it
djgodlike
Posts: 32
Joined: Wednesday 27 January 2016 16:37
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Netherlands
Contact:

Re: philips air purifier

Post by djgodlike »

Nice plugin Devguy!! Thanks. Nice to control my Philips AC3829/10.

I added the device and it shows up with sensors and switches, but all 0 readings..
In the log it gives this Error: (Ventilator Slaapkamer) Unexpected error 'PyAirControl' object has no attribute 'client_key'

Can you adres this error? or could it be my router blocking communicating from the IOT network..
Aeon Labs Gen5 USB
Greenwave Powernode 6 NS310
2x Greenwave Powernode 1 NS310
Philips Hue
Logitech media Server
Plugwise Smile P1
packetloss
Posts: 43
Joined: Monday 03 August 2015 20:27
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.11590
Location: Belgium
Contact:

Re: philips air purifier

Post by packetloss »

devguy wrote: Sunday 14 February 2021 17:48 The posted scripts here are wrappers around py-air-control. It's a nice tool but not dealing the right way with the COAP protocol that is being used by my Philips device (AC3829/10). If you read out the sensor values once in a while there is no issue, but don't use this for continuously polling like Domoticz. The fundamental wrong way that py-air-control reads out the sensor values make the network stack of the device crash after a certain time. This can be solved by disconnecting the device from the power...

The device expects clients that are interested in updates to subscribe using the COAP protocol. The device keeps pushing updated values to the client without any additional request. This is something py-air-control doesn't support.

I uploaded my solution on GitHub. It's a plugin for Domoticz. It's only tested with the AC3829/10 device. You can find it on https://github.com/roldoe/domoticz-philips-air
Hi! I installed your plugin in the latest Domoticz, for two air purifiers (1000i and 2000i) devices were made on my installation. But sadly.. they are not updated, zero results. Logging:

Code: Select all

Feb 13 17:57:59 domoticz domoticz: 1000i little bedroom: Create device [ERROR] Message image 0
Feb 13 17:57:59 domoticz domoticz: 1000i little bedroom: Connecting to Philips device on IP 192.168.16.27 using COAP
Feb 13 17:58:04 domoticz domoticz: 1000i little bedroom: Failed connecting to device...
Feb 13 18:08:02 domoticz domoticz: 1000i little bedroom: Lost connection to device, restart...
I am sure it's not firewalling issue, because nmap 192.168.16.28 says:
PORT STATE SERVICE
80/tcp open http


So I am wondering.. can anybody tell me if the 1000i (https://www.usa.philips.com/c-p/AC1214_ ... r-purifier) and 2000i (https://www.philips.de/c-p/AC2889_10/20 ... ftreiniger) do actually work with COAP? And if not, if there's another plugin I can use?
noyes
Posts: 1
Joined: Thursday 01 December 2022 15:38
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: philips air purifier

Post by noyes »

I think Philips did some changes in FW since my AC2729/50 stops working
djgodlike
Posts: 32
Joined: Wednesday 27 January 2016 16:37
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta
Location: Netherlands
Contact:

Re: philips air purifier

Post by djgodlike »

There seems to be a new way of communicating with our purifiers..

https://github.com/iobroker-community-a ... hilips-air

Can someone build a plugin from this resource? :)
Aeon Labs Gen5 USB
Greenwave Powernode 6 NS310
2x Greenwave Powernode 1 NS310
Philips Hue
Logitech media Server
Plugwise Smile P1
Post Reply

Who is online

Users browsing this forum: No registered users and 0 guests