diff --git a/include/hass.h b/include/hass.h new file mode 100644 index 0000000..6573188 --- /dev/null +++ b/include/hass.h @@ -0,0 +1,8 @@ +#ifndef HAS_WEBSOCKET_H +#define HAS_WEBSOCKET_H + +#define HASS_ADDRESS "home.drath.win" +#define HASS_TOKEN "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI0MzUxMTZiY2VjNTg0MTI3OGI4YmU0NTY4ZGQ5MzIyYiIsImlhdCI6MTc1NzQzMDI0MCwiZXhwIjoyMDcyNzkwMjQwfQ.6wKTlxEA0FLWfv-qW35vewUSvTxdVrZWqFwHT5Khu6E" +#define HASS_ENTITY "sensor.gniazdko_komputer_moc" + +#endif \ No newline at end of file diff --git a/src/hass.c b/src/hass.c new file mode 100644 index 0000000..711a6f8 --- /dev/null +++ b/src/hass.c @@ -0,0 +1,155 @@ +#include +#include "log.h" +#include "hass.h" + +char tx[512]; +struct lws_context *context = nullptr; +struct lws *websock = nullptr; +float state; +uint16_t id = 2; + +static int callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len); + +static int callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { + (void)user; + (void)len; + // ArduinoJson::JsonDocument json; + switch (reason) { + case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: { + applog(LOG_ERR, "websocket conn error: %s", in ? (char *)in : "(null)"); + return -1; + } + + // case LWS_CALLBACK_CLIENT_RECEIVE: { + // ArduinoJson::deserializeJson(json, (char *)in); + // std::string ha_type = json["type"].as(); + // // std::println("[HomeAssistant] got event type: {} ", ha_type); + // + // if (ha_type == "auth_required") { + // json.clear(); + // json["type"] = "auth"; + // json["access_token"] = HASS_TOKEN; + // ArduinoJson::serializeJson(json, tx); + // break; + // } + // + // if (ha_type == "auth_ok") { + // std::println("[HomeAssistant] subscribing to entity \"{}\"", HASS_ENTITY); + // json.clear(); + // json["id"] = id++; + // json["type"] = "subscribe_entities"; + // json["entity_ids"][0] = HASS_ENTITY; + // ArduinoJson::serializeJson(json, tx); + // break; + // } + // + // if (ha_type == "result") { + // if (json["success"].as() == "false") + // std::println("[HomeAssistant] api said success was \"false\" on message id {}", id - 1); + // break; + // } + // + // if (ha_type == "event") { + // state = json["event"]["c"][HASS_ENTITY]["+"]["s"].as(); + // break; + // } + // + // std::println("[HomeAssistant] unhandled event: {}", (char *)in); + // break; + // } + + case LWS_CALLBACK_CLIENT_ESTABLISHED: { + applog(LOG_INF, "Websocket connected"); + break; + } + + case LWS_CALLBACK_CLIENT_CLOSED: { + applog(LOG_INF, "Websocket closed"); + return -1; + } + + case LWS_CALLBACK_CLIENT_WRITEABLE: { + /* skip whole callback if there's no tx to send */ + const size_t txlen = strlen(tx); + + if (txlen > 0) { + // std::println("[HomeAssistant] sending {}", tx); + const size_t msgLen = LWS_PRE + txlen; + unsigned char *buf = (unsigned char *)malloc(msgLen); + if (buf) { + memcpy(&buf[LWS_PRE], tx, txlen); + lws_write(wsi, &buf[LWS_PRE], txlen, LWS_WRITE_TEXT); + tx[0] = '\0'; + free(buf); + } + } + break; + } + + default: + break; + } + + return 0; +} + +int hass_connect() { + struct lws_client_connect_info i = {}; + struct lws_context_creation_info info = {}; + + lws_set_log_level(LLL_ERR | LLL_WARN, lwsl_emit_syslog); + + static const struct lws_protocols protocols[] = { + {"lws-minimal-client", callback, 0, 0, 0, NULL, 0}, + LWS_PROTOCOL_LIST_TERM}; + + static const struct lws_extension extensions[] = { + {"permessage-deflate", + lws_extension_callback_pm_deflate, + "permessage-deflate" + "; client_no_context_takeover" + "; client_max_window_bits"}, + {nullptr, nullptr, nullptr}}; + + info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; + info.port = CONTEXT_PORT_NO_LISTEN; + info.protocols = protocols; + info.fd_limit_per_thread = 1 + 1 + 1; + info.extensions = extensions; + + context = lws_create_context(&info); + if (!context) { + applog(LOG_ERR, "error creating context"); + return -1; + } + + i.context = context; + i.port = 443; + i.address = HASS_ADDRESS; + i.path = "/api/websocket"; + i.host = i.address; + i.origin = i.address; + i.ssl_connection = LCCSCF_USE_SSL | LCCSCF_PRIORITIZE_READS; + i.protocol = nullptr; + i.local_protocol_name = "lws-minimal-client"; + + websock = lws_client_connect_via_info(&i); + if (!websock) { + applog(LOG_ERR, " error creating lws client"); + return -1; + } + return 0; +} + +void hass_poll() { + lws_service(context, 0); + lws_callback_on_writable(websock); +} + +float hass_get() { + return state; +} + +void hass_disconnect() { + lws_context_destroy(context); +} \ No newline at end of file