implement gpio output via mqtt

This commit is contained in:
technyon
2023-06-04 12:38:31 +02:00
parent 356b34b293
commit b7053db767
7 changed files with 110 additions and 22 deletions

View File

@@ -151,6 +151,18 @@ const std::vector<PinEntry> &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);
}

1
Gpio.h
View File

@@ -57,6 +57,7 @@ public:
const std::vector<uint8_t>& availablePins() const;
const std::vector<PinEntry>& pinConfiguration() const;
const PinRole getPinRole(const int& pin) const;
String getRoleDescription(PinRole role) const;
void getConfigurationText(String& text, const std::vector<PinEntry>& pinConfiguration, const String& linebreak = "\n") const;

View File

@@ -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"

View File

@@ -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();

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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;