diff --git a/Gpio.cpp b/Gpio.cpp index c9dedfa..9d396d2 100644 --- a/Gpio.cpp +++ b/Gpio.cpp @@ -151,6 +151,18 @@ const std::vector &Gpio::pinConfiguration() const return _pinConfiguration; } +const PinRole Gpio::getPinRole(const int &pin) const +{ + for(const auto& pinEntry : _pinConfiguration) + { + if(pinEntry.pin == pin) + { + return pinEntry.role; + } + } + return PinRole::Disabled; +} + String Gpio::getRoleDescription(PinRole role) const { switch(role) @@ -315,3 +327,4 @@ void Gpio::migrateObsoleteSetting() delay(200); restartEsp(RestartReason::GpioConfigurationUpdated); } + diff --git a/Gpio.h b/Gpio.h index 4481014..af9d7ae 100644 --- a/Gpio.h +++ b/Gpio.h @@ -57,6 +57,7 @@ public: const std::vector& availablePins() const; const std::vector& pinConfiguration() const; + const PinRole getPinRole(const int& pin) const; String getRoleDescription(PinRole role) const; void getConfigurationText(String& text, const std::vector& pinConfiguration, const String& linebreak = "\n") const; diff --git a/MqttTopics.h b/MqttTopics.h index d1a5568..b5ae1ff 100644 --- a/MqttTopics.h +++ b/MqttTopics.h @@ -63,4 +63,6 @@ #define mqtt_topic_network_device "/maintenance/networkDevice" #define mqtt_topic_gpio_prefix "/gpio" -#define mqtt_topic_gpio_input "/input_" +#define mqtt_topic_gpio_pin "/pin_" +#define mqtt_topic_gpio_role "/role" +#define mqtt_topic_gpio_state "/state" diff --git a/Network.cpp b/Network.cpp index 654178d..3457ad6 100644 --- a/Network.cpp +++ b/Network.cpp @@ -213,21 +213,36 @@ void Network::initialize() _publishDebugInfo = _preferences->getBool(preference_publish_debug_info); - char gpioPath[200]; + char gpioPath[250]; + bool rebGpio = rebuildGpio(); - for(const auto& pinEntry : _gpio->pinConfiguration()) + if(rebGpio) { - switch(pinEntry.role) + Log->println(F("Rebuild MQTT GPIO structure")); + } + for (const auto &pinEntry: _gpio->pinConfiguration()) + { + switch (pinEntry.role) { case PinRole::GeneralInput: - memset(gpioPath, 0, sizeof(gpioPath)); - buildMqttPath(gpioPath, {mqtt_topic_gpio_prefix, (mqtt_topic_gpio_input + std::to_string(pinEntry.pin)).c_str(), "role" }); - publishString(_lockPath.c_str(), gpioPath, "input"); + if(rebGpio) + { + buildMqttPath(gpioPath, {mqtt_topic_gpio_prefix, (mqtt_topic_gpio_pin + std::to_string(pinEntry.pin)).c_str(), mqtt_topic_gpio_role}); + publishString(_lockPath.c_str(), gpioPath, "input"); + buildMqttPath(gpioPath, {mqtt_topic_gpio_prefix, (mqtt_topic_gpio_pin + std::to_string(pinEntry.pin)).c_str(), mqtt_topic_gpio_state}); + publishString(_lockPath.c_str(), gpioPath, std::to_string(digitalRead(pinEntry.pin)).c_str()); + } break; case PinRole::GeneralOutput: - memset(gpioPath, 0, sizeof(gpioPath)); - buildMqttPath(gpioPath, {mqtt_topic_gpio_prefix, (mqtt_topic_gpio_input + std::to_string(pinEntry.pin)).c_str(), "role" }); - publishString(_lockPath.c_str(), gpioPath, "output"); + if(rebGpio) + { + buildMqttPath(gpioPath, {mqtt_topic_gpio_prefix, (mqtt_topic_gpio_pin + std::to_string(pinEntry.pin)).c_str(), mqtt_topic_gpio_role}); + publishString(_lockPath.c_str(), gpioPath, "output"); + buildMqttPath(gpioPath, {mqtt_topic_gpio_prefix, (mqtt_topic_gpio_pin + std::to_string(pinEntry.pin)).c_str(), mqtt_topic_gpio_state}); + publishString(_lockPath.c_str(), gpioPath, "0"); + } + buildMqttPath(gpioPath, {mqtt_topic_gpio_prefix, (mqtt_topic_gpio_pin + std::to_string(pinEntry.pin)).c_str(), mqtt_topic_gpio_state}); + subscribe(_lockPath.c_str(), gpioPath); break; } } @@ -509,11 +524,6 @@ void Network::registerMqttReceiver(MqttReceiver* receiver) void Network::onMqttDataReceivedCallback(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total) { - if(millis() < _ignoreSubscriptionsTs) - { - return; - } - uint8_t value[50] = {0}; size_t l = min(len, sizeof(value)-1); @@ -525,14 +535,53 @@ void Network::onMqttDataReceivedCallback(const espMqttClientTypes::MessageProper _inst->onMqttDataReceived(properties, topic, value, len, index, total); } -void Network::onMqttDataReceived(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total) +void Network::onMqttDataReceived(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t& len, size_t& index, size_t& total) { + parseGpioTopics(properties, topic, payload, len, index, total); + + if(millis() < _ignoreSubscriptionsTs) + { + return; + } + for(auto receiver : _mqttReceivers) { receiver->onMqttDataReceived(topic, (byte*)payload, index); } } + +void Network::parseGpioTopics(const espMqttClientTypes::MessageProperties &properties, const char *topic, const uint8_t *payload, size_t& len, size_t& index, size_t& total) +{ + char gpioPath[250]; + buildMqttPath(gpioPath, {_lockPath.c_str(), mqtt_topic_gpio_prefix, mqtt_topic_gpio_pin}); +// /nuki_t/gpio/pin_17/state + size_t gpioLen = strlen(gpioPath); + if(strncmp(gpioPath, topic, gpioLen) == 0) + { + char pinStr[3] = {0}; + pinStr[0] = topic[gpioLen]; + if(topic[gpioLen+1] != '/') + { + pinStr[1] = topic[gpioLen+1]; + } + + int pin = std::atoi(pinStr); + + if(_gpio->getPinRole(pin) == PinRole::GeneralOutput) + { + const uint8_t pinState = strcmp((const char*)payload, "1") == 0 ? HIGH : LOW; + Log->print(F("GPIO ")); + Log->print(pin); + Log->print(F(" (Output) --> ")); + Log->println(pinState); + digitalWrite(pin, pinState); + } + + } +} + + void Network::reconfigureDevice() { _device->reconfigure(); diff --git a/Network.h b/Network.h index 15f762c..d46cd18 100644 --- a/Network.h +++ b/Network.h @@ -75,7 +75,8 @@ public: private: static void onMqttDataReceivedCallback(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total); - void onMqttDataReceived(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total); + void onMqttDataReceived(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t& len, size_t& index, size_t& total); + void parseGpioTopics(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t& len, size_t& index, size_t& total); void setupDevice(); bool reconnect(); diff --git a/RestartReason.h b/RestartReason.h index 17752a0..9871c3f 100644 --- a/RestartReason.h +++ b/RestartReason.h @@ -25,24 +25,37 @@ enum class RestartReason #define RESTART_REASON_VALID_DETECT 0xa00ab00bc00bd00d; extern int restartReason; -extern uint64_t restartReasonValid; +extern uint64_t restartReasonValidDetect; +extern bool rebuildGpioRequested; extern RestartReason currentRestartReason; +extern bool restartReason_isValid; + + inline static void restartEsp(RestartReason reason) { + if(reason == RestartReason::GpioConfigurationUpdated) + { + rebuildGpioRequested = true; + } restartReason = (int)reason; - restartReasonValid = RESTART_REASON_VALID_DETECT; + restartReasonValidDetect = RESTART_REASON_VALID_DETECT; ESP.restart(); } inline static void initializeRestartReason() { uint64_t cmp = RESTART_REASON_VALID_DETECT; - if(restartReasonValid == cmp) + restartReason_isValid = (restartReasonValidDetect == cmp); + if(restartReason_isValid) { currentRestartReason = (RestartReason)restartReason; - memset(&restartReasonValid, 0, sizeof(restartReasonValid)); + memset(&restartReasonValidDetect, 0, sizeof(restartReasonValidDetect)); + } + else + { + rebuildGpioRequested = false; } } @@ -121,4 +134,11 @@ inline static String getEspRestartReason() default: return "Unknown: " + (int)reason; } +} + +inline bool rebuildGpio() +{ + bool rebGpio = rebuildGpioRequested; + rebuildGpioRequested = false; + return restartReason_isValid && rebGpio; } \ No newline at end of file diff --git a/main.cpp b/main.cpp index 5e0166c..ac712f2 100644 --- a/main.cpp +++ b/main.cpp @@ -34,7 +34,9 @@ bool openerEnabled = false; unsigned long restartTs = (2^32) - 5 * 60000; RTC_NOINIT_ATTR int restartReason; -RTC_NOINIT_ATTR uint64_t restartReasonValid; +RTC_NOINIT_ATTR uint64_t restartReasonValidDetect; +RTC_NOINIT_ATTR bool rebuildGpioRequested; +bool restartReason_isValid; RestartReason currentRestartReason = RestartReason::NotApplicable; TaskHandle_t networkTaskHandle = nullptr;