/* * Copyright (c) 2023, Erich Styger * * SPDX-License-Identifier: BSD-3-Clause * * Useful read: https://github.com/particle-iot/lwip/blob/master/doc/mqtt_client.txt */ #include "platform.h" #if PL_CONFIG_USE_MQTT_CLIENT #include "pico/cyw43_arch.h" #include "lwip/apps/mqtt.h" #include "lwip/dns.h" #include "mqtt_client.h" #include "dns_resolver.h" #include "McuLog.h" #include "McuUtility.h" #include "McuRTOS.h" #if PL_CONFIG_USE_MINI #include "minIni/McuMinINI.h" #include "MinIniKeys.h" #endif #if MQTT_CLIENT_IS_EV_CHARGER #include "Modbus/McuHeidelberg.h" #endif #if LWIP_TCP #define MQTT_EXTRA_LOGS (0) /* set to 1 to produce extra log output */ #if MQTT_CLIENT_IS_EV_CHARGER /* HomeAssistant Tesla Powerwall topics */ #define TOPIC_NAME_SOLAR_POWER "homeassistant/sensor/powerwall_solar_now/state" #define TOPIC_NAME_SITE_POWER "homeassistant/sensor/powerwall_load_now/state" #define TOPIC_NAME_GRID_POWER "homeassistant/sensor/powerwall_site_now/state" #define TOPIC_NAME_BATTERY_POWER "homeassistant/sensor/powerwall_battery_now/state" #define TOPIC_NAME_BATTERY_PERCENTAGE "homeassistant/sensor/powerwall_charge/state" #define TOPIC_NAME_CHARGER_CHARGING_POWER "home/charger/power" #endif /* default entries for the MQTT broker connection */ #define MQTT_DEFAULT_BROKER "homeassistant" #define MQTT_DEFAULT_CLIENT "client" #define MQTT_DEFAULT_USER "user" #define MQTT_DEFAULT_PASS "password" #define MQTT_DEFAULT_PUBLISH true #define DEFAULT_TOPIC_NAME_SENSORS_UPDATE "user/room/device/update" #define DEFAULT_TOPIC_NAME_SEND_MEASUREMENT "user/room/device/cmd/measure" typedef struct mqtt_t { mqtt_client_t *mqtt_client; /* lwIP MQTT client handle */ DnsResolver_info_t addr; /* broker lwip address, resolved by DNS if hostname is used */ unsigned char broker[32]; /* broker IP or hostname string. For hostname, DNS will be used */ unsigned char client_id[32]; /* client ID used for connection: each client should have a unique ID */ unsigned char client_user[32]; /* client user name used for connection */ unsigned char client_pass[96]; /* client user password */ unsigned char sensors_update_topic[64]; /* topic name for sensor updates */ unsigned char send_measurement_topic[64]; /* topic name for sending measurement */ topic_ID_e in_pub_ID; /* incoming published ID, set in the incoming_publish_cb and used in the incoming_data_cb */ /* configuration settings */ bool doLogging; /* if it shall write log messages */ bool doPublishing; /* if it publish messages */ } mqtt_t; static mqtt_t mqtt; /* information used for MQTT connection */ static const struct mqtt_connect_client_info_t mqtt_client_info = { mqtt.client_id, /* client ID */ mqtt.client_user, /* client user name */ mqtt.client_pass, /* client password */ 100, /* keep alive timeout in seconds */ NULL, /* will_topic */ NULL, /* will_msg */ 0, /* will_qos */ 0 /* will_retain */ #if LWIP_ALTCP && LWIP_ALTCP_TLS , NULL #endif }; // Static variable to hold the callback pointer static MqttClient_MessageCallback_t app_message_callback = NULL; void MqttClient_RegisterMessageCallback(MqttClient_MessageCallback_t cb) { app_message_callback = cb; } static void mqtt_publish_request_cb(void *arg, err_t err) { #if 0 && MQTT_EXTRA_LOGS const struct mqtt_connect_client_info_t *client_info = (const struct mqtt_connect_client_info_t*)arg; McuLog_trace("MQTT client \"%s\" publish request cb: err %d", client_info->client_id, (int)err); #endif } #if MQTT_CLIENT_IS_SENSOR int MqttClient_Publish_SensorValues(float temperature, float humidity) { err_t res; uint8_t buf[64]; const uint8_t qos = 0; /* quos: 0: fire&forget, 1: at least once */ const uint8_t retain = 0; if (!MqttClient_GetDoPublish()) { return ERR_DISABLED; } if (mqtt.mqtt_client != NULL) { /* connected? */ if (mqtt.doLogging) { McuLog_trace("publish t:%f h:%f", temperature, humidity); } McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"{\"values\": {\"temperature\": "); McuUtility_strcatNumFloat(buf, sizeof(buf), temperature, 2); McuUtility_strcat(buf, sizeof(buf), (unsigned char*)", \"humidity\": "); McuUtility_strcatNumFloat(buf, sizeof(buf), humidity, 2); McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"}}"); res = mqtt_publish(mqtt.mqtt_client, mqtt.sensors_update_topic, buf, strlen(buf), qos, retain, mqtt_publish_request_cb, NULL); if (res != ERR_OK) { McuLog_error("Failed sensor values mqtt_publish: %d", res); (void)MqttClient_Disconnect(); /* try disconnect and connect again */ (void)MqttClient_Connect(); return res; } return ERR_OK; } else { return ERR_FAILED; } } #endif #if MQTT_CLIENT_IS_EV_CHARGER int MqttClient_Publish_ChargingPower(uint32_t powerW) { err_t res; uint8_t buf[64]; const uint8_t qos = 0; /* quos: 0: fire&forget, 1: at least once */ const uint8_t retain = 0; if (!MqttClient_GetDoPublish()) { return ERR_DISABLED; } if (mqtt.mqtt_client!=NULL) { /* connected? */ if (mqtt.doLogging) { McuLog_trace("publish P: %d W", powerW); } McuUtility_strcpy(buf, sizeof(buf), (unsigned char*)"{\"chargeP\": "); McuUtility_strcatNum32u(buf, sizeof(buf), powerW); McuUtility_strcat(buf, sizeof(buf), (unsigned char*)", \"unit\": \"W\"}"); res = mqtt_publish(mqtt.mqtt_client, TOPIC_NAME_CHARGER_CHARGING_POWER, buf, strlen(buf), qos, retain, mqtt_publish_request_cb, NULL); if (res!=ERR_OK) { McuLog_error("Failed charging power mqtt_publish: %d", res); (void)MqttClient_Disconnect(); /* try disconnect and connect again */ (void)MqttClient_Connect(); return res; } return ERR_OK; } else { return ERR_FAILED; } } #endif bool MqttClient_GetDoPublish(void) { return mqtt.doPublishing && mqtt.mqtt_client!=NULL; } void MqttClient_SetDoPublish(bool publish) { #if PL_CONFIG_USE_MINI McuMinINI_ini_putl(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_PUBLISH, publish, NVMC_MININI_FILE_NAME); #endif mqtt.doPublishing = publish; } int MqttClient_Publish(const unsigned char *topic, const unsigned char *value) { err_t res; uint8_t buf[64]; const uint8_t qos = 0; /* quos: 0: fire&forget, 1: at least once */ const uint8_t retain = 0; if (!MqttClient_GetDoPublish()) { return ERR_DISABLED; } if (mqtt.mqtt_client!=NULL) { /* connected? */ if (mqtt.doLogging) { McuLog_trace("publish topic: \"%s\" value: \"%s\"", topic, value); } res = mqtt_publish(mqtt.mqtt_client, topic, value, strlen(value), qos, retain, mqtt_publish_request_cb, NULL); if (res!=ERR_OK) { McuLog_error("Failed mqtt_publish: %d", res); (void)MqttClient_Disconnect(); /* try disconnect and connect again */ (void)MqttClient_Connect(); return res; } return ERR_OK; } else { return ERR_FAILED; } } static void GetDataString(unsigned char *buf, size_t bufSize, const u8_t *data, u16_t len) { buf[0] = '\0'; for(int i=0; i 1000, * "1.2" => 1200, "3.025" = 3025, "-1.002" = -1002 */ int32_t watt; float f; if (sscanf(str, "%f", &f)!=1) { /* check number of conversions, shall be 1 */ McuLog_error("failed conversion of %s", str); return 0; /* conversion failed, return 0 */ } watt = (int)(f*1000.0f); return watt; } #endif static void mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags) { const struct mqtt_connect_client_info_t *client_info = (const struct mqtt_connect_client_info_t*)arg; LWIP_UNUSED_ARG(data); unsigned char buf[32]; int32_t watt; #if MQTT_EXTRA_LOGS McuLog_trace("MQTT client \"%s\" data cb: len %d, flags %d", client_info->client_id, (int)len, (int)flags); #endif if(flags & MQTT_DATA_FLAG_LAST) { /* Last fragment of payload received (or whole part if payload fits receive buffer. See MQTT_VAR_HEADER_BUFFER_LEN) */ #if MQTT_CLIENT_IS_EV_CHARGER if (mqtt.in_pub_ID == Topic_ID_Solar_Power) { GetDataString(buf, sizeof(buf), data, len); if (mqtt.doLogging) { McuLog_trace("solarP: %s kW", buf); } watt = scanWattValue(buf); if (watt>=0) { /* can only be positive */ McuHeidelberg_SetSolarPowerWatt(watt); } } else if(mqtt.in_pub_ID == Topic_ID_Site_Power) { GetDataString(buf, sizeof(buf), data, len); if (mqtt.doLogging) { McuLog_trace("siteP: %s kW", buf); } watt = scanWattValue(buf); if (watt>=0) { /* can only be positive */ McuHeidelberg_SetSitePowerWatt(watt); } } else if(mqtt.in_pub_ID == Topic_ID_Grid_Power) { GetDataString(buf, sizeof(buf), data, len); if (mqtt.doLogging) { McuLog_trace("gridP: %s kW", buf); } watt = scanWattValue(buf); McuHeidelberg_SetGridPowerWatt(watt); } else if(mqtt.in_pub_ID == Topic_ID_Battery_Power) { GetDataString(buf, sizeof(buf), data, len); if (mqtt.doLogging) { McuLog_trace("battP: %s, kW", buf); } } else if(mqtt.in_pub_ID == Topic_ID_Battery_Percentage) { GetDataString(buf, sizeof(buf), data, len); if (mqtt.doLogging) { McuLog_trace("bat%%: %s%%", buf); } #elif MQTT_CLIENT_IS_SENSOR if (app_message_callback != NULL) { app_message_callback(mqtt.in_pub_ID, data, len); #endif } else { McuLog_trace("mqtt_incoming_data_cb: Ignoring payload..."); } } else { McuLog_trace("mqtt_incoming_data_cb: fragmented payload ..."); /* Handle fragmented payload, store in buffer, write to file or whatever */ } } static void mqtt_incoming_publish_cb(void *arg, const char *topic, u32_t tot_len) { const struct mqtt_connect_client_info_t *client_info = (const struct mqtt_connect_client_info_t*)arg; #if MQTT_CLIENT_IS_EV_CHARGER if (McuUtility_strcmp(topic, TOPIC_NAME_SOLAR_POWER)==0) { mqtt.in_pub_ID = Topic_ID_Solar_Power; } else if (McuUtility_strcmp(topic, TOPIC_NAME_SITE_POWER)==0) { mqtt.in_pub_ID = Topic_ID_Site_Power; } else if (McuUtility_strcmp(topic, TOPIC_NAME_GRID_POWER)==0) { mqtt.in_pub_ID = Topic_ID_Grid_Power; } else if (McuUtility_strcmp(topic, TOPIC_NAME_BATTERY_POWER)==0) { mqtt.in_pub_ID = Topic_ID_Battery_Power; } else if (McuUtility_strcmp(topic, TOPIC_NAME_BATTERY_PERCENTAGE)==0) { mqtt.in_pub_ID = Topic_ID_Battery_Percentage; } else if (McuUtility_strcmp(topic, TOPIC_NAME_CHARGER_CHARGING_POWER)==0) { mqtt.in_pub_ID = Topic_ID_Charging_Power; #elif MQTT_CLIENT_IS_SENSOR if (McuUtility_strcmp(topic, mqtt.sensors_update_topic)==0) { mqtt.in_pub_ID = Topic_ID_Sensor_Update; } else if (McuUtility_strcmp(topic, mqtt.send_measurement_topic)==0) { mqtt.in_pub_ID = Topic_ID_Send_Measurement; #endif } else { /* unknown */ McuLog_trace("MQTT client \"%s\" publish cb: topic %s, len %d", client_info->client_id, topic, (int)tot_len); mqtt.in_pub_ID = Topic_ID_None; } } static void mqtt_request_cb(void *arg, err_t err) { #if MQTT_EXTRA_LOGS const struct mqtt_connect_client_info_t *client_info = (const struct mqtt_connect_client_info_t*)arg; McuLog_trace("MQTT client \"%s\" request cb: err %d", client_info->client_id, (int)err); #endif } static void mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status) { const struct mqtt_connect_client_info_t *client_info = (const struct mqtt_connect_client_info_t*)arg; LWIP_UNUSED_ARG(client); err_t err; #if MQTT_EXTRA_LOGS McuLog_trace("MQTT client \"%s\" connection cb: status %d", client_info->client_id, (int)status); #endif if (status!=MQTT_CONNECT_ACCEPTED) { McuLog_error("MQTT client \"%s\" connection cb: FAILED status %d", client_info->client_id, (int)status); } /* subscribe to topics */ if (status == MQTT_CONNECT_ACCEPTED) { McuLog_trace("MQTT connect accepted"); #if MQTT_CLIENT_IS_EV_CHARGER err = mqtt_sub_unsub(client, TOPIC_NAME_SOLAR_POWER, /* solar P in kW */ 1, /* quos: 0: fire&forget, 1: at least once */ mqtt_request_cb, /* callback */ LWIP_CONST_CAST(void*, client_info), 1 /* subscribe */ ); if (err!=ERR_OK) { McuLog_error("failed subscribing, err %d", err); } err = mqtt_sub_unsub(client, TOPIC_NAME_SITE_POWER, /* site/house P in kW */ 1, /* quos */ mqtt_request_cb, LWIP_CONST_CAST(void*, client_info), 1); if (err!=ERR_OK) { McuLog_error("failed subscribing, err %d", err); } err = mqtt_sub_unsub(client, TOPIC_NAME_GRID_POWER, /* grid P in kW */ 1, /* quos */ mqtt_request_cb, LWIP_CONST_CAST(void*, client_info), 1); if (err!=ERR_OK) { McuLog_error("failed subscribing, err %d", err); } err = mqtt_sub_unsub(client, TOPIC_NAME_BATTERY_POWER, /* battery P in kW */ 1, /* quos */ mqtt_request_cb, LWIP_CONST_CAST(void*, client_info), 1); if (err!=ERR_OK) { McuLog_error("failed subscribing, err %d", err); } err = mqtt_sub_unsub(client, TOPIC_NAME_BATTERY_PERCENTAGE, /* topic: percentage of battery charge */ 1, /* quos */ mqtt_request_cb, LWIP_CONST_CAST(void*, client_info), 1); if (err!=ERR_OK) { McuLog_error("failed subscribing, err %d", err); } #elif MQTT_CLIENT_IS_SENSOR err = mqtt_sub_unsub(client, mqtt.send_measurement_topic, /* topic: send measurement command */ 1, /* quality of service */ mqtt_request_cb, // Callback to call when subscribe/unsubscribe response is received LWIP_CONST_CAST(void*, client_info), 1); // 1 for subscribe, 0 for unsubscribe if (err!=ERR_OK) { McuLog_error("failed subscribing, err %d", err); } #endif } else if (status==MQTT_CONNECT_DISCONNECTED) { McuLog_trace("MQTT connect disconnect"); } } #endif /* LWIP_TCP */ uint8_t MqttClient_Connect(void) { #if LWIP_TCP int nofRetry; mqtt.mqtt_client = mqtt_client_new(); /* create client handle */ err_t err; if (mqtt.mqtt_client==NULL) { McuLog_fatal("new mqtt client is NULL"); } /* setup connection information */ #if PL_CONFIG_USE_MINI McuMinINI_ini_gets(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_BROKER, MQTT_DEFAULT_BROKER, mqtt.broker, sizeof(mqtt.broker), NVMC_MININI_FILE_NAME); McuMinINI_ini_gets(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_CLIENT, MQTT_DEFAULT_CLIENT, mqtt.client_id, sizeof(mqtt.client_id), NVMC_MININI_FILE_NAME); McuMinINI_ini_gets(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_USER, MQTT_DEFAULT_USER, mqtt.client_user, sizeof(mqtt.client_user), NVMC_MININI_FILE_NAME); McuMinINI_ini_gets(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_PASS, MQTT_DEFAULT_PASS, mqtt.client_pass, sizeof(mqtt.client_pass), NVMC_MININI_FILE_NAME); McuMinINI_ini_gets(NVMC_MININI_SECTION_MQTT, NVMC_TOPIC_NAME_SENSORS_UPDATE, DEFAULT_TOPIC_NAME_SENSORS_UPDATE, mqtt.sensors_update_topic, sizeof(mqtt.sensors_update_topic), NVMC_MININI_FILE_NAME); McuMinINI_ini_gets(NVMC_MININI_SECTION_MQTT, NVMC_TOPIC_NAME_SEND_MEASUREMENT, DEFAULT_TOPIC_NAME_SEND_MEASUREMENT, mqtt.send_measurement_topic, sizeof(mqtt.send_measurement_topic), NVMC_MININI_FILE_NAME); mqtt.doPublishing = McuMinINI_ini_getbool(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_PASS, MQTT_DEFAULT_PUBLISH, NVMC_MININI_FILE_NAME); #else McuUtility_strcpy(mqtt.broker, sizeof(mqtt.broker), MQTT_DEFAULT_BROKER); McuUtility_strcpy(mqtt.client_id, sizeof(mqtt.client_id), MQTT_DEFAULT_CLIENT); McuUtility_strcpy(mqtt.client_user, sizeof(mqtt.client_user), MQTT_DEFAULT_USER); McuUtility_strcpy(mqtt.client_pass, sizeof(mqtt.client_pass), MQTT_DEFAULT_PASS); mqtt.doPublishing = MQTT_DEFAULT_PUBLISH; #endif /* resolve host name to IP address: */ for (nofRetry=60; nofRetry>=0; nofRetry--) { if (DnsResolver_ResolveName(mqtt.broker, &mqtt.addr, 5*1000)!=0) { /* use DNS to resolve name to IP address */ McuLog_error("failed to resolve broker name %s, retry ...", mqtt.broker); vTaskDelay(pdMS_TO_TICKS(5000)); } else { break; /* success! leaving loop */ } } if (nofRetry<0) { McuLog_fatal("failed to resolve broker name %s, giving up", mqtt.broker); return ERR_FAILED; } /* setup callbacks for incoming data: */ mqtt_set_inpub_callback( mqtt.mqtt_client, /* client handle */ mqtt_incoming_publish_cb, /* callback for incoming publish messages */ mqtt_incoming_data_cb, /* callback for incoming data */ LWIP_CONST_CAST(void*, &mqtt_client_info) /* argument for callbacks */ ); /* connect to broker */ cyw43_arch_lwip_begin(); /* start section for to lwIP access */ err = mqtt_client_connect( mqtt.mqtt_client, /* client handle */ &mqtt.addr.resolved_addr, /* broker IP address */ MQTT_PORT, /* port to be used */ mqtt_connection_cb, LWIP_CONST_CAST(void*, &mqtt_client_info), /* connection callback with argument */ &mqtt_client_info /* client information */ ); cyw43_arch_lwip_end(); /* end section accessing lwIP */ if (err!=ERR_OK) { McuLog_error("failed connecting client to server"); } else { McuLog_trace("client connecting"); } return err; #else return ERR_FAILED; #endif /* LWIP_TCP */ } uint8_t MqttClient_Disconnect(void) { if (mqtt.mqtt_client!=NULL) { McuLog_trace("disconnecting client"); cyw43_arch_lwip_begin(); /* start section for to lwIP access */ mqtt_disconnect(mqtt.mqtt_client); mqtt_client_free(mqtt.mqtt_client); cyw43_arch_lwip_end(); /* end section accessing lwIP */ mqtt.mqtt_client = NULL; } return ERR_OK; } static uint8_t SetBroker(const unsigned char *broker) { unsigned char buf[64]; McuUtility_ScanDoubleQuotedString(&broker, buf, sizeof(buf)); McuUtility_strcpy(mqtt.broker, sizeof(mqtt.broker), buf); #if PL_CONFIG_USE_MINI McuMinINI_ini_puts(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_BROKER, mqtt.broker, NVMC_MININI_FILE_NAME); #endif return ERR_OK; } static uint8_t SetID(const unsigned char *id) { unsigned char buf[64]; McuUtility_ScanDoubleQuotedString(&id, buf, sizeof(buf)); McuUtility_strcpy(mqtt.client_id, sizeof(mqtt.client_id), buf); #if PL_CONFIG_USE_MINI McuMinINI_ini_puts(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_CLIENT, mqtt.client_id, NVMC_MININI_FILE_NAME); #endif return ERR_OK; } static uint8_t SetUser(const unsigned char *user) { unsigned char buf[64]; McuUtility_ScanDoubleQuotedString(&user, buf, sizeof(buf)); McuUtility_strcpy(mqtt.client_user, sizeof(mqtt.client_user), buf); #if PL_CONFIG_USE_MINI McuMinINI_ini_puts(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_USER, mqtt.client_user, NVMC_MININI_FILE_NAME); #endif return ERR_OK; } static uint8_t SetPassword(const unsigned char *pass) { unsigned char buf[96]; McuUtility_ScanDoubleQuotedString(&pass, buf, sizeof(buf)); McuUtility_strcpy(mqtt.client_pass, sizeof(mqtt.client_pass), buf); #if PL_CONFIG_USE_MINI McuMinINI_ini_puts(NVMC_MININI_SECTION_MQTT, NVMC_MININI_KEY_MQTT_PASS, mqtt.client_pass, NVMC_MININI_FILE_NAME); #endif return ERR_OK; } static uint8_t PrintStatus(const McuShell_StdIOType *io) { McuShell_SendStatusStr((unsigned char*)"mqttclient", (unsigned char*)"mqttclient status\r\n", io->stdOut); McuShell_SendStatusStr((unsigned char*)" log", mqtt.doLogging?(unsigned char*)"on\r\n":(unsigned char*)"off\r\n", io->stdOut); McuShell_SendStatusStr((unsigned char*)" publish", MqttClient_GetDoPublish()?(unsigned char*)"on\r\n":(unsigned char*)"off\r\n", io->stdOut); McuShell_SendStatusStr((unsigned char*)" client", mqtt.mqtt_client==NULL?(unsigned char*)"diconnected\r\n":(unsigned char*)"connected\r\n", io->stdOut); McuShell_SendStatusStr((unsigned char*)" broker", mqtt.broker, io->stdOut); McuShell_SendStr((unsigned char*)"\r\n", io->stdOut); McuShell_SendStatusStr((unsigned char*)" client ID", mqtt.client_id, io->stdOut); McuShell_SendStr((unsigned char*)"\r\n", io->stdOut); McuShell_SendStatusStr((unsigned char*)" client user", mqtt.client_user, io->stdOut); McuShell_SendStr((unsigned char*)"\r\n", io->stdOut); McuShell_SendStatusStr((unsigned char*)" client password", mqtt.client_pass, io->stdOut); McuShell_SendStr((unsigned char*)"\r\n", io->stdOut); return ERR_OK; } static uint8_t PrintHelp(const McuShell_StdIOType *io) { McuShell_SendHelpStr((unsigned char*)"mqttclient", (unsigned char*)"Group of mqttclient commands\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" help|status", (unsigned char*)"Print help or status information\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" log on|off", (unsigned char*)"Turn logging on or off\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" publish on|off", (unsigned char*)"Publishing on or off\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" connect|disconnect", (unsigned char*)"Connect or disconnect from server\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" set broker \"\"", (unsigned char*)"Set broker name\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" set id \"\"", (unsigned char*)"Set client ID\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" set user \"\"", (unsigned char*)"Set client user name\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" set pass \"\"", (unsigned char*)"Set client password\r\n", io->stdOut); McuShell_SendHelpStr((unsigned char*)" pub \"\" \"\"", (unsigned char*)"Publish text to a topic\r\n", io->stdOut); return ERR_OK; } uint8_t MqttClient_ParseCommand(const unsigned char *cmd, bool *handled, const McuShell_StdIOType *io) { const unsigned char *p; uint16_t val16u; if (McuUtility_strcmp((char*)cmd, McuShell_CMD_HELP)==0 || McuUtility_strcmp((char*)cmd, "mqttclient help")==0) { *handled = true; return PrintHelp(io); } else if ((McuUtility_strcmp((char*)cmd, McuShell_CMD_STATUS)==0) || (McuUtility_strcmp((char*)cmd, "mqttclient status")==0)) { *handled = true; return PrintStatus(io); } else if (McuUtility_strcmp((char*)cmd, "mqttclient log on")==0) { *handled = true; mqtt.doLogging = true; } else if (McuUtility_strcmp((char*)cmd, "mqttclient log off")==0) { *handled = true; mqtt.doLogging = false; } else if (McuUtility_strcmp((char*)cmd, "mqttclient publish on")==0) { *handled = true; MqttClient_SetDoPublish(true); } else if (McuUtility_strcmp((char*)cmd, "mqttclient publish off")==0) { *handled = true; MqttClient_SetDoPublish(false); } else if (McuUtility_strcmp((char*)cmd, "mqttclient connect")==0) { *handled = true; MqttClient_Connect(); } else if (McuUtility_strcmp((char*)cmd, "mqttclient disconnect")==0) { *handled = true; MqttClient_Disconnect(); } else if (McuUtility_strncmp((char*)cmd, "mqttclient set broker ", sizeof("mqttclient set broker ")-1)==0) { *handled = TRUE; p = cmd + sizeof("mqttclient set broker ")-1; return SetBroker(p); } else if (McuUtility_strncmp((char*)cmd, "mqttclient set id ", sizeof("mqttclient set id ")-1)==0) { *handled = TRUE; p = cmd + sizeof("mqttclient set id ")-1; return SetID(p); } else if (McuUtility_strncmp((char*)cmd, "mqttclient set user ", sizeof("mqttclient set user ")-1)==0) { *handled = TRUE; p = cmd + sizeof("mqttclient set user ")-1; return SetUser(p); } else if (McuUtility_strncmp((char*)cmd, "mqttclient set pass ", sizeof("mqttclient set pass ")-1)==0) { *handled = TRUE; p = cmd + sizeof("mqttclient set pass ")-1; return SetPassword(p); } else if (McuUtility_strncmp((char*)cmd, "mqttclient pub ", sizeof("mqttclient pub ")-1)==0) { unsigned char topic[128], text[128]; *handled = TRUE; p = cmd + sizeof("mqttclient pub ")-1; if (McuUtility_ScanDoubleQuotedString(&p, topic, sizeof(topic))!=ERR_OK) { return ERR_FAILED; } McuUtility_SkipSpaces(&p); if (McuUtility_ScanDoubleQuotedString(&p, text, sizeof(text))!=ERR_OK) { return ERR_FAILED; } return MqttClient_Publish(topic, text); } return ERR_OK; } void MqttClient_Deinit(void) { MqttClient_Disconnect(); } void MqttClient_Init(void) { mqtt.doLogging = true; mqtt.doPublishing = MQTT_DEFAULT_PUBLISH; } #endif /* PL_CONFIG_USE_MQTT_CLIENT */