04.10.2019, 08:49
Yes it works, i can switch the Dyson off, with the follow command (code is not perfect, but you can use it as start for yourself):
My library
You can also make an event handler like:
Code:
12
require('user.nit_dyson')
runCommand(5,CMD_OFF)My library
Code:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
--[[
use getDevices('email@email.com','password') to get the encrypted password and fill it in dysons[] so you can use this offline.
--]]
-- product types
DYSON_PURE_COOL_LINK_TOUR = '475'
DYSON_PURE_COOL_LINK_DESK = '469'
DYSON_PURE_HOT_COOL_LINK_TOUR = '455'
DYSON_360_EYE = 'N223'
DYSON_PURE_HOT_COOL_2018 = '527' --HP04 Dyson Pure Hot+Cool 2018 (244289-01)
CMD_OFF = '{"fpwr":"OFF"}'
-- all dyson devices
dysons = {} -- room(not used), ip, port(default 1883), type, username/serial, password
dysons[5] = {'Room', '192.168.x.xxx', 1883, DYSON_PURE_HOT_COOL_2018, 'A1B-EU-KNAXXXXX', 'verylongencryptedpasswordfromgetdevices'}
-- get devices from web portal
function getDevices(iPortalUser, iPortalPwd)
https = require 'ssl.https'
require('json')
socket.http.TIMEOUT = 5
local cUsername = iPortalUser
local cPassword = iPortalPwd
-- get session info
local cBody1 = '{"Email":"' .. cUsername .. '","Password":"' .. cPassword ..'"}'
local cReq1 = {}
local cUrl1 = 'https://api.cp.dyson.com/v1/userregistration/authenticate?country=NL'
result1 = https.request({
url = cUrl1,
method = 'POST',
headers = {
['content-length'] = #cBody1,
['content-type'] = 'application/json'
},
source = ltn12.source.string(cBody1),
sink = ltn12.sink.table(cReq1)
})
if result1 and cReq1 then
cReq1 = table.concat(cReq1)
cReq1 = json.pdecode(cReq1)
cAccount = nil
cPassword = nil
if cReq1 then
if cReq1.Account and cReq1.Password then
cAccount = cReq1.Account
cPassword = cReq1.Password
end
end
--log(cAccount,cPassword)
else
log(result1)
end
mime = require("mime")
local cAuth = "Basic " .. mime.b64(cAccount..":"..cPassword)
local cReq2 = {}
local cUrl2 = 'https://api.cp.dyson.com/v2/provisioningservice/manifest' -- v2 for new devices
result2, c, h = https.request({
url = cUrl2,
method = 'GET',
headers = {
['authorization'] = cAuth
},
sink = ltn12.sink.table(cReq2)
})
--log(result2,c,h)
log(cReq2)
end
-- decrypt password
function decryptPwd(iPwd)
data = iPwd
-- create key
key = {}
for i = 1, 32 do
key[ #key + 1 ] = i
end
key = string.char(unpack(key))
-- decrypt data
data = require('encdec').base64dec(data)
aes = require('user.aes')
aes_256_cbc, err = aes:new(key, nil, aes.cipher(256, 'cbc'), { iv = string.rep('\0', 16) }, nil, 0)
data = aes_256_cbc:decrypt(data)
-- unpad data
len = string.byte(data, #data) + 1
data = data:sub(1, -len)
-- decode json
data, err = require('json').pdecode(data)
if type(data) == 'table' then
pass = data.apPasswordHash
end
--log(pass)
return pass
end
-- run dyson command
function runCommand(IDevice, iCmd)
broker = dysons[IDevice][2]
port = dysons[IDevice][3]
producttype = dysons[IDevice][4]
username = dysons[IDevice][5]
password = dysons[IDevice][6]
-- after this initialization, you'll have to use the hashed password to connect to the fan. The hashed password is a base64 encoded of the sha512 of the password
passwordDec = decryptPwd(password)
topicCmd = producttype .. '/' .. username .. '/command'
mqtt = require('mosquitto')
client = mqtt.new()
client.ON_CONNECT = function(status, rc, err)
if status then
payload = '{"msg":"STATE-SET", "time":"'..os.date("%Y-%m-%dT%H:%M:%SZ")..'", "data":'..iCmd..'}'
client:publish(topicCmd, payload)
end
end
client.ON_PUBLISH = function()
client:disconnect()
end
client:login_set(username, passwordDec)
client:connect(broker, port)
client:loop_forever()
endYou can also make an event handler like:
Code:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
require('user.nit_dyson')
broker = '192.168.x.xx'
port = 1883 -- default port is 1883
username = 'A1B-EU-KNAXXXXX' -- device serial
password = 'longpassword'
passwordDec = decryptPwd(password)
producttype = DYSON_PURE_HOT_COOL_2018
topic = producttype .. '/' .. username .. '/status/current'
topicCmd = producttype .. '/' .. username .. '/command'
mqtt = require('mosquitto')
client = mqtt.new()
client.ON_CONNECT = function(status, rc, err)
if status then
log('connect ok')
client:subscribe(topic)
--payload = '{"msg":"STATE-SET", "time":"'..os.date("%Y-%m-%dT%H:%M:%SZ")..'", "data":{"fpwr":"OFF"}}'
--client:publish(topicCmd, payload)
else
log('connect error', rc, err)
end
end
client.ON_MESSAGE = function(mid, topic, data)
log('message', topic, data)
end
client.ON_PUBLISH = function()
--log('publish')
--client:disconnect()
end
client.ON_LOG = function()
--log('log')
end
client.ON_DISCONNECT = function()
--log('disconnect')
end
client:login_set(username, passwordDec)
client:connect(broker, port)
client:loop_forever()