Open syu-lk4b opened 7 years ago
my air zhimi,airpurifier.v1 firmware version is 1.4.0
pi@stevenhomesmart:~/Git/temp $ node air.js AirPurifier { domain: null, _events: {}, _eventsCount: 0, _maxListeners: undefined, id: undefined, type: 'air-purifier', model: 'zhimi.airpurifier.v1', capabilities: [ 'power', 'mode', 'sensor', 'temperature', 'humidity', 'aqi' ], address: '192.168.88.23', port: 54321, writeOnly: false, packet: Packet { header: <Buffer 21 31 00 80 00 00 00 00 00 00 ce 32 00 00 d8 68 3e 3e f1 97 3c 76 37 f3 02 aa b0 b6 e1 c1 23 7b>, _serverStampTime: 1495860174359, _token: <Buffer 0c c7 49 b4 c2 12 4f c6 7f 43 5e 93 c0 04 53 78>, _tokenKey: <Buffer 26 50 49 f0 bf 8d ec 89 96 fe fb da 46 4d 3b 93>, _tokenIV: <Buffer 85 e2 5b de f3 92 ba d2 d1 33 74 e1 fe 38 a9 4b>, data: <Buffer 7b 22 72 65 73 75 6c 74 22 3a 5b 6e 75 6c 6c 2c 22 69 64 6c 65 22 2c 6e 75 6c 6c 2c 6e 75 6c 6c 2c 6e 75 6c 6c 2c 34 31 2c 31 36 37 2c 36 30 2c 6e 75 ... >, _serverStamp: 55400 }, socket: Socket { domain: null, _events: { message: [Function: bound _onMessage] }, _eventsCount: 1, _maxListeners: undefined, _handle: UDP { fd: 12, lookup: [Function: lookup4], owner: [Circular], onmessage: [Function: onMessage] }, _receiving: true, _bindState: 2, type: 'udp4', fd: -42, _reuseAddr: undefined, _queue: undefined }, _id: 1, _promises: {}, _hasFailedToken: false, _properties: { power: false, mode: 'idle', favoriteLevel: null, temperature: 0, humidity: null, aqi: 41, bright: 167, filterLifeRemaining: 60, filterHoursUsed: null, useTime: null, led: false, ledBrightness: 'unknown', buzzer: true }, _propertiesToMonitor: [ 'power', 'mode', 'favorite_level', 'temp_dec', 'humidity', 'aqi', 'bright', 'filter1_life', 'f1_hour_used', 'use_time', 'led', 'led_b', 'buzzer' ], _propertyDefinitions: { power: { mapper: [Function] }, mode: { mapper: [Function: IDENTITY_MAPPER] }, favorite_level: { name: 'favoriteLevel', mapper: [Function: IDENTITY_MAPPER] }, temp_dec: { name: 'temperature', mapper: [Function: mapper] }, humidity: { mapper: [Function: IDENTITY_MAPPER] }, aqi: { mapper: [Function: IDENTITY_MAPPER] }, bright: { mapper: [Function: IDENTITY_MAPPER] }, filter1_life: { name: 'filterLifeRemaining', mapper: [Function: IDENTITY_MAPPER] }, f1_hour_used: { name: 'filterHoursUsed', mapper: [Function: IDENTITY_MAPPER] }, use_time: { name: 'useTime', mapper: [Function: IDENTITY_MAPPER] }, led: { mapper: [Function: mapper] }, led_b: { name: 'ledBrightness', mapper: [Function: mapper] }, buzzer: { mapper: [Function: mapper] } }, _reversePropertyDefinitions: { favoriteLevel: 'favorite_level', temperature: 'temp_dec', filterLifeRemaining: 'filter1_life', filterHoursUsed: 'f1_hour_used', useTime: 'use_time', ledBrightness: 'led_b' }, _loadProperties: [Function: bound _loadProperties], management: DeviceManagement { device: [Circular] }, debug: { [Function: debug] namespace: 'miio.device.[192.168.88.23]', enabled: false, useColors: true, color: 5, inspectOpts: {} }, setPower: [Function], _propertyMonitor: Timeout { _called: false, _idleTimeout: 30000, _idlePrev: TimersList { _idleNext: [Circular], _idlePrev: [Circular], _timer: [Object], _unrefed: false, msecs: 30000, nextTick: false }, _idleNext: TimersList { _idleNext: [Circular], _idlePrev: [Circular], _timer: [Object], _unrefed: false, msecs: 30000, nextTick: false }, _idleStart: 645, _onTimeout: [Function: bound _loadProperties], _timerArgs: undefined, _repeat: 30000 }, _lastToken: 1495860172177 }
Thanks for the report! It looks to me like zhimi.airpurifier.v1
doesn't share the same API as newer models. I based the initial air purifier code on the methods I could see coming from my own air purifier which is zhimi.airpurifier.m1
.
Does calling set_mode
work for turning it on and off? idle
should turn it off and auto
should turn it on.
If you feel up for it you can read Protocol and commands to see how you can create a packet capture and find the correct methods to use.
If set_mode
works I can easily add a workaround that uses that to your this model of airpurifier on and off. And if you figure out more about how what methods work on the device I'll be more than happy to add support for those too.
Thanks man,I'll try to testing it tonight, and let you know if that's the case, again, thanks the reply
got 404 for the doc of how to get the tokens https://github.com/aholstenson/miio/blob/master/docs/tokens.md
btw, tested the set_mode function ,it's also not supported.
1): Error: Method set_mode
is not supported
Thank you for the details, it seems like the zhimi.airpurifier.v1
has a completely different API. For now I'll disable the support in the next release.
I'm more than happy to readd support if you or anyone else can figure out what methods and properties it uses. Doing so is a bit tricky and involves packet capturing via a local Android emulator, Protocol and commands contains an intro and links to further docs.
this is the wireshark dump, I am pretty sure I have capture all the command UDP package. but When I tested as Protocol and commands shows from PackageSender , it doesnt' give any feedback. is there anything that I done wrong ? any suggestion or advise?
syu-mbp-15 :: ~/git_repo/miio ‹master› » miio --token "0cc749b4c2124fc67f435e93c0045378" --json-dump /tmp/test.json undefined:1
SyntaxError: Unexpected end of JSON input
at Object.parse (native)
at Object.
syu-mbp-15 :: ~ » miio --discover 1 ↵ INFO Discovering devices. Press Ctrl+C to stop.
Device ID: 52038474 Model info: lumi.gateway.v3 (gateway) Address: 192.168.88.111 (lumi-gateway-v3_miio52038474) Token: ??? Support: At least basic
Device ID: 46778211 Model info: Unknown Address: 192.168.88.228 (esp_c28b4e) Token: ??? Support: Unknown
Device ID: 52786 Model info: zhimi.airpurifier.v1 (air-purifier) Address: 192.168.88.23 (zhimi-airpurifier-v1_miio52786) Token: 0cc749b4c2124fc67f435e93c0045378 via auto-token Support: At least basic
Thanks. Sorry for the late reply. Did you export the packet capture as a JSON-file? The error looks like it might not be a JSON.
After I exported your provided capture I get this:
-> 192.168.88.16 data= N/A
<- 192.168.88.23 data= N/A
-> 192.168.88.16 data= {"id":10,"method":"set_mode","params":["auto"]}
<- 192.168.88.23 data= {"result":["ok"],"id":10}
-> 192.168.88.16 data= {"id":11,"method":"get_prop","params":["aqi","filter1_life","led","mode","act_det","buzzer"]}
<- 192.168.88.23 data= {"result":[42,60,"on","auto","off","on"],"id":11}
-> 192.168.88.16 data= {"id":12,"method":"set_mode","params":["silent"]}
<- 192.168.88.23 data= {"result":["ok"],"id":12}
-> 192.168.88.16 data= {"id":13,"method":"set_mode","params":["auto"]}
<- 192.168.88.23 data= {"result":["ok"],"id":13}
-> 192.168.88.16 data= {"id":14,"method":"get_prop","params":["aqi","filter1_life","led","mode","act_det","buzzer"]}
<- 192.168.88.23 data= {"result":[47,60,"on","auto","off","on"],"id":14}
-> 192.168.88.16 data= {"id":15,"method":"set_mode","params":["silent"]}
<- 192.168.88.23 data= {"result":["ok"],"id":15}
-> 192.168.88.16 data= {"id":16,"method":"set_mode","params":["strong"]}
<- 192.168.88.23 data= {"result":["ok"],"id":16}
-> 192.168.88.16 data= {"id":17,"method":"get_prop","params":["aqi","filter1_life","led","mode","act_det","buzzer"]}
<- 192.168.88.23 data= {"result":[44,60,"on","strong","off","on"],"id":17}
-> 192.168.88.16 data= {"id":18,"method":"set_mode","params":["auto"]}
<- 192.168.88.23 data= {"result":["ok"],"id":18}
-> 192.168.88.16 data= {"id":19,"method":"set_mode","params":["idle"]}
<- 192.168.88.23 data= {"result":["ok"],"id":19}
-> 192.168.88.16 data= {"id":20,"method":"get_prop","params":["aqi","filter1_life","led","mode","act_det","buzzer"]}
<- 192.168.88.23 data= {"result":[44,60,"off","idle","off","on"],"id":20}
-> 192.168.88.16 data= {"id":21,"method":"set_mode","params":["auto"]}
<- 192.168.88.23 data= {"result":["ok"],"id":21}
-> 192.168.88.16 data= {"id":22,"method":"get_prop","params":["aqi","filter1_life","led","mode","act_det","buzzer"]}
<- 192.168.88.23 data= {"result":[43,60,"on","auto","off","on"],"id":22}
-> 192.168.88.16 data= {"id":23,"method":"set_mode","params":["idle"]}
<- 192.168.88.23 data= {"result":["ok"],"id":23}
-> 192.168.88.16 data= {"id":24,"method":"set_mode","params":["auto"]}
<- 192.168.88.23 data= {"result":["ok"],"id":24}
-> 192.168.88.16 data= {"id":25,"method":"set_mode","params":["idle"]}
<- 192.168.88.23 data= {"result":["ok"],"id":25}
-> 192.168.88.16 data= {"id":26,"method":"get_prop","params":["aqi","filter1_life","led","mode","act_det","buzzer"]}
<- 192.168.88.23 data= {"result":[43,60,"off","idle","off","on"],"id":26}
It looks like set_mode
is being used with values of idle
, auto
, silent' and
strong`. That should be enough for me to add in some initial support.
Thanks man, i am not sure what you mean capture as a Json file ,will take a look that. is there anything else that I can help provide?
change the code a little bit ,yes, set_mode works
syu-mbp-15 :: ~/Desktop/js » node set.js 192.168.88.23 power auto [ 'ok' ] syu-mbp-15 :: ~/Desktop/js » 255 ↵ syu-mbp-15 :: ~/Desktop/js » 255 ↵ syu-mbp-15 :: ~/Desktop/js » node set.js 192.168.88.23 power idle 255 ↵ [ 'ok' ] syu-mbp-15 :: ~/Desktop/js »
@Stevenyu1982 how to set? thx
Having same issue generating capture as JSON
JSON file contained: {}
sudo miio --token 661bc1e355a15ed4197398e229a3ff20 --json-dump file.json
/usr/lib/node_modules/miio/cli/index.js:427
packets.forEach(p => {
^
TypeError: packets.forEach is not a function
at Object.<anonymous> (/usr/lib/node_modules/miio/cli/index.js:427:10)
at Module._compile (module.js:571:32)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.runMain (module.js:605:10)
at run (bootstrap_node.js:427:7)
at startup (bootstrap_node.js:151:9)
at bootstrap_node.js:542:3
if JSON file does not exist, it does not create the file and prompts error:
sudo miio --token 661bc1e355a15ed4197398e229a3ff20 --json-dump file fs.js:584 return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode); ^
Error: ENOENT: no such file or directory, open 'file'
at Object.fs.openSync (fs.js:584:18)
at Object.fs.readFileSync (fs.js:491:33)
at Object.<anonymous> (/usr/lib/node_modules/miio/cli/index.js:421:18)
at Module._compile (module.js:571:32)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.runMain (module.js:605:10)
at run (bootstrap_node.js:427:7)
@sibero80 The miio
tool doesn't generate any JSON dumps, those are created from Wireshark. Have a look at the protocol documentation for more details.
tried the power plug ,works fine, but the same function doesn't work in zhimi,airpurifier.v1 from the document ,it says have't tested, trying hookup it with homebridge-miio, but if miio doesn't support it ,then homebridge-miio wont' work for sure.
any idea?
here is my device
Device ID: 45531555 Model info: zimi.powerstrip.v2 (power-strip) Address: 192.168.88.55 (zimi-powerstrip-v2_miio45531555) Token: 4407cd577d6f7787fd63a759fc9fdf95 via auto-token Support: At least basic
Device ID: 937021 Model info: chuangmi.plug.v1 (power-plug) Address: 192.168.88.18 (chuangmi-plug-v1_miio937021) Token: a6ab080d5223bdbc73fbf572ef8388dc via auto-token Support: At least basic
Device ID: 52786 Model info: zhimi.airpurifier.v1 (air-purifier) Address: 192.168.88.23 (zhimi-airpurifier-v1_miio52786) Token: 0cc749b4c2124fc67f435e93c0045378 via auto-token Support: At least basic
the script output
pi@stevenhomesmart:~/Git/temp $ node set.js 192.168.88.23 power on { Error: Method
set_power
is not supported at Object.reject (/usr/lib/node_modules/miio/lib/device.js:213:13) at AirPurifier._onMessage (/usr/lib/node_modules/miio/lib/device.js:104:8) at emitTwo (events.js:106:13) at Socket.emit (events.js:191:7) at UDP.onMessage (dgram.js:549:8) code: -10000 } pi@stevenhomesmart:~/Git/temp $ ls^C pi@stevenhomesmart:~/Git/temp $ node set.js 192.168.88.55 power on [ 'ok' ] pi@stevenhomesmart:~/Git/temp $ node set.js 192.168.88.18 power on [ 'ok' ] pi@stevenhomesmart:~/Git/temp $ node set.js 192.168.88.18 power off [ 'ok' ] pi@stevenhomesmart:~/Git/temp $here is the script that i use
!/usr/bin/node
/ eslint-disable /
// Location of miio node lib const miio = require('miio');
// No need to change any lines in this section var deviceip = process.argv[2]; var secondarg = process.argv[3]; var thirdarg = process.argv[4]; function exit() { process.exit(-1); }
// Power On (on / off specified as on or off) if ( secondarg === "power" ) { setTimeout(exit, 7000); miio.device({ address: deviceip }).then(device => { return device.call('set_power', [thirdarg]) .then(console.log) .catch(console.error); })}
// Status if ( secondarg === "status" ) { setTimeout(exit, 7000); miio.device({ address: deviceip }).then(device => { return device.call('get_prop', ["humidity","temp_dec","power","mode","led_b","buzzer","child_lock","limit_hum","trans_level"]) .then(console.log) .catch(console.error); })}
// Status temperature and humidity only if ( secondarg === "status2" ) { setTimeout(exit, 7000); miio.device({ address: deviceip }).then(device => { return device.call('get_prop', ["temp_dec","humidity"]) .then(console.log) .catch(console.error); })}
// Set mode (silent, medium or high) if ( secondarg === "mode" ) { setTimeout(exit, 7000); miio.device({ address: deviceip }).then(device => { return device.call('set_mode', [thirdarg]) .then(console.log) .catch(console.error); })}
// Set buzzer (on or off) if ( secondarg === "buzzer" ) { setTimeout(exit, 7000); miio.device({ address: deviceip }).then(device => { return device.call('set_buzzer', [thirdarg]) .then(console.log) .catch(console.error); })}
// led if ( secondarg === "led" ) { setTimeout(exit, 7000); miio.device({ address: deviceip }).then(device => { return device.call('set_led_b', [JSON.parse(thirdarg)]) .then(console.log) .catch(console.error); })}
// Humidity limit percent (specified as 40, 50, 60, 70 or 80) if ( secondarg === "humiditylimit" ) { setTimeout(exit, 7000); miio.device({ address: deviceip }).then(device => { return device.call('set_limit_hum', [JSON.parse(thirdarg)]) .then(console.log) .catch(console.error); })}