add mqtt, decouple i2c and sensor
This commit is contained in:
199
ha_mqtt.c
Normal file
199
ha_mqtt.c
Normal file
@@ -0,0 +1,199 @@
|
||||
// ha_mqtt.c
|
||||
|
||||
#include "ha_mqtt.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lwip/apps/mqtt.h"
|
||||
#include "lwip/ip4_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "systick.h"
|
||||
|
||||
// config
|
||||
#define MQTT_BROKER_IP_A 192
|
||||
#define MQTT_BROKER_IP_B 168
|
||||
#define MQTT_BROKER_IP_C 102
|
||||
#define MQTT_BROKER_IP_D 1
|
||||
#define MQTT_BROKER_PORT 1883
|
||||
#define MQTT_CLIENT_ID "gxht30_sensor_node"
|
||||
#define MQTT_RECONNECT_INTERVAL_MS 5000
|
||||
|
||||
#define DEVICE_UNIQUE_ID "gxht30_board_01"
|
||||
#define DEVICE_NAME "Office Climate Sensor"
|
||||
#define DEVICE_MANUFACTURER "me"
|
||||
#define DEVICE_MODEL "GXHT30-ETH-v1"
|
||||
|
||||
// home assistant topics
|
||||
#define HA_DISCOVERY_PREFIX "homeassistant"
|
||||
|
||||
#define TEMP_UNIQUE_ID DEVICE_UNIQUE_ID "_temperature"
|
||||
#define TEMP_CONFIG_TOPIC \
|
||||
HA_DISCOVERY_PREFIX "/sensor/" TEMP_UNIQUE_ID "/config"
|
||||
#define TEMP_STATE_TOPIC "devices/" DEVICE_UNIQUE_ID "/temperature/state"
|
||||
#define TEMP_NAME "Temperature"
|
||||
|
||||
#define HUM_UNIQUE_ID DEVICE_UNIQUE_ID "_humidity"
|
||||
#define HUM_CONFIG_TOPIC HA_DISCOVERY_PREFIX "/sensor/" HUM_UNIQUE_ID "/config"
|
||||
#define HUM_STATE_TOPIC "devices/" DEVICE_UNIQUE_ID "/humidity/state"
|
||||
#define HUM_NAME "Humidity"
|
||||
|
||||
#define MQTT_RECONNECT_INTERVAL_MS 5000
|
||||
|
||||
static mqtt_client_t* s_mqtt_client;
|
||||
static ip_addr_t s_mqtt_broker_ip;
|
||||
static uint8_t s_mqtt_connected = 0;
|
||||
static uint32_t s_last_mqtt_retry_time = 0;
|
||||
|
||||
extern struct netif g_netif;
|
||||
|
||||
static void publish_ha_discovery_configs(mqtt_client_t* client);
|
||||
static void mqtt_pub_request_cb(void* arg, err_t err);
|
||||
static void mqtt_connection_cb(mqtt_client_t* client, void* arg,
|
||||
mqtt_connection_status_t status);
|
||||
static void publish_sensor_value(const char* topic, int32_t value_x100);
|
||||
|
||||
// public fns
|
||||
|
||||
void ha_mqtt_init(void) {
|
||||
s_mqtt_client = mqtt_client_new();
|
||||
if (s_mqtt_client == NULL) {
|
||||
printf("error: failed to create mqtt client\n");
|
||||
return;
|
||||
}
|
||||
|
||||
IP4_ADDR(&s_mqtt_broker_ip, MQTT_BROKER_IP_A, MQTT_BROKER_IP_B,
|
||||
MQTT_BROKER_IP_C, MQTT_BROKER_IP_D);
|
||||
|
||||
ha_mqtt_check_and_reconnect();
|
||||
}
|
||||
|
||||
void ha_mqtt_publish_sensor_data(int32_t temp_x100, int32_t hum_x100) {
|
||||
if (!s_mqtt_connected) {
|
||||
return;
|
||||
}
|
||||
publish_sensor_value(TEMP_STATE_TOPIC, temp_x100);
|
||||
publish_sensor_value(HUM_STATE_TOPIC, hum_x100);
|
||||
}
|
||||
|
||||
void ha_mqtt_check_and_reconnect(void) {
|
||||
if (s_mqtt_connected || !netif_is_up(&g_netif) ||
|
||||
!netif_is_link_up(&g_netif) || netif_ip4_addr(&g_netif)->addr == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (millis() - s_last_mqtt_retry_time > MQTT_RECONNECT_INTERVAL_MS) {
|
||||
printf("attempting to connect to mqtt broker\n");
|
||||
|
||||
const struct mqtt_connect_client_info_t client_info = {
|
||||
.client_id = MQTT_CLIENT_ID,
|
||||
.keep_alive = 60,
|
||||
// .client_user = "user", // authentication
|
||||
// .client_pass = "pass",
|
||||
};
|
||||
|
||||
err_t err =
|
||||
mqtt_client_connect(s_mqtt_client, &s_mqtt_broker_ip, MQTT_BROKER_PORT,
|
||||
mqtt_connection_cb, NULL, &client_info);
|
||||
|
||||
if (err != ERR_OK) {
|
||||
printf("mqtt connect failed with immediate error: %d\n", err);
|
||||
}
|
||||
s_last_mqtt_retry_time = millis();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ha_mqtt_is_connected(void) { return s_mqtt_connected; }
|
||||
|
||||
// static fns
|
||||
|
||||
/**
|
||||
* @brief Publishes a sensor value after formatting it from a fixed-point
|
||||
* int
|
||||
* @param topic The MQTT topic to publish to.
|
||||
* @param value_x100 The sensor value, scaled by 100.
|
||||
*/
|
||||
static void publish_sensor_value(const char* topic, int32_t value_x100) {
|
||||
char payload_buf[16];
|
||||
|
||||
// format the fixed-point value (e.g., 2345) into a decimal string ("23.45")
|
||||
int32_t val_int = value_x100 / 100;
|
||||
int32_t val_frac = value_x100 % 100;
|
||||
if (val_frac < 0) {
|
||||
val_frac = -val_frac;
|
||||
}
|
||||
snprintf(payload_buf, sizeof(payload_buf), "%ld.%02ld", val_int, val_frac);
|
||||
|
||||
err_t err = mqtt_publish(s_mqtt_client, topic, payload_buf,
|
||||
strlen(payload_buf), 1, 0, NULL, NULL);
|
||||
|
||||
if (err != ERR_OK) {
|
||||
printf("failed to publish to topic %s: %d\n", topic, err);
|
||||
}
|
||||
}
|
||||
|
||||
static void publish_ha_discovery_configs(mqtt_client_t* client) {
|
||||
char payload[512];
|
||||
err_t err;
|
||||
|
||||
// publish temperature sensor config
|
||||
snprintf(
|
||||
payload, sizeof(payload),
|
||||
"{"
|
||||
"\"name\":\"%s\",\"unique_id\":\"%s\",\"stat_t\":\"%s\","
|
||||
"\"dev_cla\":\"temperature\",\"unit_of_meas\":\"°C\","
|
||||
"\"val_tpl\":\"{{ value|float(2) }}\","
|
||||
"\"dev\":{\"ids\":[\"%s\"],\"name\":\"%s\",\"mf\":\"%s\",\"mdl\":\"%s\"}"
|
||||
"}",
|
||||
TEMP_NAME, TEMP_UNIQUE_ID, TEMP_STATE_TOPIC, DEVICE_UNIQUE_ID,
|
||||
DEVICE_NAME, DEVICE_MANUFACTURER, DEVICE_MODEL);
|
||||
|
||||
printf("publishing ha discovery for temperature...\n");
|
||||
err = mqtt_publish(client, TEMP_CONFIG_TOPIC, payload, strlen(payload), 1, 1,
|
||||
mqtt_pub_request_cb, NULL);
|
||||
if (err != ERR_OK) {
|
||||
printf("failed to publish temp config: %d\n", err);
|
||||
}
|
||||
|
||||
// publish humidity sensor config
|
||||
snprintf(
|
||||
payload, sizeof(payload),
|
||||
"{"
|
||||
"\"name\":\"%s\",\"unique_id\":\"%s\",\"stat_t\":\"%s\","
|
||||
"\"dev_cla\":\"humidity\",\"unit_of_meas\":\"%%\","
|
||||
"\"val_tpl\":\"{{ value|float(2) }}\","
|
||||
"\"dev\":{\"ids\":[\"%s\"],\"name\":\"%s\",\"mf\":\"%s\",\"mdl\":\"%s\"}"
|
||||
"}",
|
||||
HUM_NAME, HUM_UNIQUE_ID, HUM_STATE_TOPIC, DEVICE_UNIQUE_ID, DEVICE_NAME,
|
||||
DEVICE_MANUFACTURER, DEVICE_MODEL);
|
||||
|
||||
printf("publishing ha discovery for humidity...\n");
|
||||
err = mqtt_publish(client, HUM_CONFIG_TOPIC, payload, strlen(payload), 1, 1,
|
||||
mqtt_pub_request_cb, NULL);
|
||||
if (err != ERR_OK) {
|
||||
printf("failed to publish hum config: %d\n", err);
|
||||
}
|
||||
}
|
||||
|
||||
static void mqtt_pub_request_cb(void* arg, err_t err) {
|
||||
(void)arg;
|
||||
|
||||
if (err != ERR_OK) {
|
||||
printf("mqtt publish failed with error: %d\n", err);
|
||||
}
|
||||
}
|
||||
|
||||
static void mqtt_connection_cb(mqtt_client_t* client, void* arg,
|
||||
mqtt_connection_status_t status) {
|
||||
(void)arg;
|
||||
|
||||
if (status == MQTT_CONNECT_ACCEPTED) {
|
||||
printf("mqtt connection successful\n");
|
||||
s_mqtt_connected = 1;
|
||||
// on connect, publish the discovery configuration messages
|
||||
publish_ha_discovery_configs(client);
|
||||
} else {
|
||||
printf("mqtt connection failed, status: %d. will retry.\n", status);
|
||||
s_mqtt_connected = 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user