Created
January 12, 2020 12:09
-
-
Save 3lbios/81ac3989071a13a7fb43d51279d4cd9b to your computer and use it in GitHub Desktop.
Xiaomi Mi Purifier automation daemon in Perl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
use strict; | |
use warnings; | |
# how to install mirobo and discover Mi devices: | |
# https://python-miio.readthedocs.io/en/latest/index.html | |
# substitute device IP and token from 'mirobo discover' | |
my $common_cmd = 'mirobo --ip <PURIFIER_IP> --token <PURIFIER_TOKEN>'; | |
my $aqi_cmd = $common_cmd . ' raw-command get_prop \'["aqi"]\' 2>&1'; | |
my $mode_cmd = $common_cmd . ' raw-command get_prop \'["mode"]\' 2>&1'; | |
my $setfav_cmd = $common_cmd . ' raw-command set_mode \'["favorite"]\' 2>&1'; | |
my $setauto_cmd = $common_cmd . ' raw-command set_mode \'["auto"]\' 2>&1'; | |
# check every 90s | |
use constant LOOP_DELAY => 90; | |
use constant DELAY_AFTER_CMD => 2; | |
# count how many times in a row AQI was below or above threshold | |
# this reduces oscillation - only switch from favorite to auto after LOWAQI_CNTMAX samples below threshold | |
# note: auto assumed to be much lower power than favorite | |
use constant LOWAQI_CNTMAX => 8; # prefer to stay in favorite mode longer | |
use constant HIGHAQI_CNTMAX => 2; # two high aqi samples in a row -> switch to favorite | |
use constant AQI_THRESHOLD_HIGH => 24; | |
use constant AQI_THRESHOLD_LOW => 11; | |
my $lowaqi_cnt = 0; | |
my $highaqi_cnt = 0; | |
my $cur_mode = ""; | |
while(1) { | |
# get current mode | |
$cur_mode = ""; | |
my $out = `$mode_cmd`; | |
sleep(DELAY_AFTER_CMD); | |
if ($? == 0 and $out !~ /error/i) { | |
my @words = split /\n/, $out; | |
if (@words >= 2) { | |
$words[1] =~ /\['(\w+)'\]/; | |
$cur_mode = $1; | |
} | |
} | |
# get AQI | |
$out = `$aqi_cmd`; | |
sleep(DELAY_AFTER_CMD); | |
if ($? == 0 and $out !~ /error/i) { | |
my $aqi = 0; | |
my @words = split /\n/, $out; | |
if (@words >= 2) { | |
$words[1] =~ /\[(\d+)\]/; | |
$aqi = $1; | |
} | |
# set fav mode on high AQI, auto mode on low AQI | |
if ($aqi >= AQI_THRESHOLD_HIGH) { | |
# reset lowaqi counter on any high AQI event | |
$lowaqi_cnt = 0; | |
$highaqi_cnt += 1; | |
if ($highaqi_cnt >= HIGHAQI_CNTMAX) { | |
if ($cur_mode !~ /favorite/) { | |
`$setfav_cmd`; | |
sleep(DELAY_AFTER_CMD); | |
} | |
$highaqi_cnt = 0; | |
} | |
} | |
if ($aqi <= AQI_THRESHOLD_LOW) { | |
$highaqi_cnt = 0; | |
$lowaqi_cnt += 1; | |
if ($lowaqi_cnt >= LOWAQI_CNTMAX) { | |
if ($cur_mode !~ /auto/) { | |
`$setauto_cmd`; | |
sleep(DELAY_AFTER_CMD); | |
} | |
$lowaqi_cnt = 0; | |
} | |
} | |
} else { | |
# got error response from xiaomi | |
# calling set_mode seems to unblock xiaomi (weird) | |
$lowaqi_cnt = 0; | |
$highaqi_cnt = 0; | |
if ($cur_mode =~ /favorite/) { | |
`$setfav_cmd`; | |
} else { | |
`$setauto_cmd`; | |
} | |
sleep(DELAY_AFTER_CMD); | |
} | |
sleep(LOOP_DELAY); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment