# @module # @desc Home Assistant helper import json var ha = module("ha") ha.init = def(url, token) ha.base = url ha.token = token end # Internal request options ha.options = def() return { "headers": { "Authorization": "Bearer " + ha.token, "Content-Type": "application/json" } } end # ha.entity(entity_id, cb) # # cb(data, error) # # data: # { # "entity_id": "...", # "state": "...", # "attributes": {...} # } ha.entity = def(entity_id, cb) var url = ha.base + "/api/states/" + entity_id http.get(url, def(body, status) if status != 200 cb(nil, "http " + str(status)) return end if body == nil cb(nil, "empty response") return end var data = json.load(body) if data == nil cb(nil, "bad json") return end if !isinstance(data, map) cb(nil, "invalid response") return end cb(data, nil) end, ha.options()) end # ha.state(entity_id, cb) # # cb(value, error) # # Home Assistant state. ha.state = def(entity_id, cb) ha.entity(entity_id, def(data, error) if error != nil cb(nil, error) return end var value = data.find("state") if value == nil cb(nil, "state not found") return end cb(value, nil) end) end # ha.attribute(entity_id, attribute_name, cb) # # cb(value, error) ha.attribute = def(entity_id, attribute_name, cb) ha.entity(entity_id, def(data, error) if error != nil cb(nil, error) return end var attrs = data.find("attributes") if attrs == nil || !isinstance(attrs, map) cb(nil, "attributes not found") return end var value = attrs.find(attribute_name) if value == nil cb(nil, "attribute not found: " + attribute_name) return end cb(value, nil) end) end # ha.number(entity_id, cb) # # Отримує state to real. ha.number = def(entity_id, cb) ha.state(entity_id, def(value, error) if error != nil cb(nil, error) return end try cb(real(value), nil) except cb(nil, "state is not numeric: " + str(value)) end end) end # ha.int(entity_id, cb) # # Отримує state to int ha.int = def(entity_id, cb) ha.number(entity_id, def(value, error) if error != nil cb(nil, error) return end if value >= 0 cb(int(value + 0.5), nil) else cb(int(value - 0.5), nil) end end) end # ha.attribute_number(entity_id, attribute_name, cb) # # Attr as real. ha.attribute_number = def(entity_id, attribute_name, cb) ha.attribute(entity_id, attribute_name, def(value, error) if error != nil cb(nil, error) return end try cb(real(value), nil) except cb(nil, "attribute is not numeric: " + str(value)) end end) end # ha.attribute_int(entity_id, attribute_name, cb) # # Attr as int. ha.attribute_int = def(entity_id, attribute_name, cb) ha.attribute_number(entity_id, attribute_name, def(value, error) if error != nil cb(nil, error) return end if value >= 0 cb(int(value + 0.5), nil) else cb(int(value - 0.5), nil) end end) end # ha.call(domain, service, data, cb, return_response) # # cb(data, error) # # Generic Home Assistant service call. # When return_response is true, returns service_response if HA provides it. ha.call = def(domain, service, data, cb, return_response) if data == nil data = {} end var url = ha.base + "/api/services/" + domain + "/" + service if return_response url = url + "?return_response" end var body = json.dump(data) var options = ha.options() # ha.options() уже має Authorization. # Додаємо обов'язковий тип POST body. var headers = options.find("headers") if !isinstance(headers, map) headers = {} options["headers"] = headers end headers["Content-Type"] = "application/json" log("POST " + url) log("BODY " + body) http.post( url, body, def(response_body, status) log("STATUS " + str(status)) log("RESPONSE " + str(response_body)) if response_body == nil cb(nil, "HA request failed: " + str(status)) return end var response = nil try response = json.load(response_body) except cb(nil, "HA returned invalid JSON") return end if !isinstance(response, map) cb(nil, "HA returned invalid response") return end if return_response var service_response = response.find("service_response") if service_response == nil cb(nil, "service_response not found") return end cb(service_response, nil) return end cb(response, nil) end, options ) end # ha.weather_forecasts(entity_id, forecast_type, cb) # # cb(service_response, error) # forecast_type: "hourly", "daily" or "twice_daily" ha.weather_forecasts = def(entity_id, forecast_type, cb) ha.call( "weather", "get_forecasts", { "entity_id": entity_id, "type": forecast_type }, cb, true ) end return ha