set gpio output depending on lock state

This commit is contained in:
technyon
2023-04-07 14:00:05 +02:00
parent e3237a648c
commit a30b716869
5 changed files with 128 additions and 32 deletions

View File

@@ -6,23 +6,20 @@
#include "PreferencesKeys.h"
Gpio* Gpio::_inst = nullptr;
NukiWrapper* Gpio::_nuki = nullptr;
unsigned long Gpio::_lockedTs = 0;
unsigned long Gpio::_debounceTs = 0;
const uint Gpio::_debounceTime = 1000;
Gpio::Gpio(Preferences* preferences, NukiWrapper* nuki)
Gpio::Gpio(Preferences* preferences)
: _preferences(preferences)
{
_inst = this;
loadPinConfiguration();
_inst->init(nuki);
_inst->init();
}
void Gpio::init(NukiWrapper* nuki)
void Gpio::init()
{
_nuki = nuki;
for(const auto& entry : _inst->_pinConfiguration)
{
const auto it = std::find(_inst->availablePins().begin(), _inst->availablePins().end(), entry.pin);
@@ -118,6 +115,19 @@ const std::vector<PinEntry> &Gpio::pinConfiguration() const
return _pinConfiguration;
}
PinRole Gpio::getPinRole(uint8_t pin)
{
for(const auto& entry : _pinConfiguration)
{
if(entry.pin == pin)
{
return entry.role;
}
}
return PinRole::Disabled;
}
String Gpio::getRoleDescription(PinRole role) const
{
switch(role)
@@ -147,6 +157,7 @@ void Gpio::getConfigurationText(String& text, const std::vector<PinEntry>& pinCo
{
if(entry.role != PinRole::Disabled)
{
text.concat("GPIO ");
text.concat(entry.pin);
if(entry.pin < 10)
{
@@ -164,23 +175,41 @@ const std::vector<PinRole>& Gpio::getAllRoles() const
return _allRoles;
}
void Gpio::notify(const GpioAction &action)
{
for(auto& callback : _callbacks)
{
callback(action);
}
}
void Gpio::addCallback(std::function<void(const GpioAction&)> callback)
{
_callbacks.push_back(callback);
}
void Gpio::isrLock()
{
if(millis() < _lockedTs) return;
_nuki->lock();
_lockedTs = millis() + _debounceTime;
if(millis() < _debounceTs) return;
_inst->notify(GpioAction::Lock);
_debounceTs = millis() + _debounceTime;
}
void Gpio::isrUnlock()
{
if(millis() < _lockedTs) return;
_nuki->unlock();
_lockedTs = millis() + _debounceTime;
if(millis() < _debounceTs) return;
_inst->notify(GpioAction::Unlock);
_debounceTs = millis() + _debounceTime;
}
void Gpio::isrUnlatch()
{
if(millis() < _lockedTs) return;
_nuki->unlatch();
_lockedTs = millis() + _debounceTime;
if(millis() < _debounceTs) return;
_inst->notify(GpioAction::Unlatch);
_debounceTs = millis() + _debounceTime;
}
void Gpio::setPinOutput(const uint8_t& pin, const uint8_t& state)
{
digitalWrite(pin, state);
}

28
Gpio.h
View File

@@ -1,7 +1,8 @@
#pragma once
#include "NukiWrapper.h"
#include <functional>
#include <Preferences.h>
#include <vector>
enum class PinRole
{
@@ -13,6 +14,13 @@ enum class PinRole
OutputHighUnlocked,
};
enum class GpioAction
{
Lock,
Unlock,
Unlatch
};
struct PinEntry
{
uint8_t pin = 0;
@@ -22,8 +30,10 @@ struct PinEntry
class Gpio
{
public:
Gpio(Preferences* preferences, NukiWrapper* nuki);
static void init(NukiWrapper* nuki);
Gpio(Preferences* preferences);
static void init();
void addCallback(std::function<void(const GpioAction&)> callback);
void loadPinConfiguration();
void savePinConfiguration(const std::vector<PinEntry>& pinConfiguration);
@@ -31,12 +41,17 @@ public:
const std::vector<uint8_t>& availablePins() const;
const std::vector<PinEntry>& pinConfiguration() const;
PinRole getPinRole(uint8_t pin);
String getRoleDescription(PinRole role) const;
void getConfigurationText(String& text, const std::vector<PinEntry>& pinConfiguration) const;
const std::vector<PinRole>& getAllRoles() const;
void setPinOutput(const uint8_t& pin, const uint8_t& state);
private:
void notify(const GpioAction& action);
const std::vector<uint8_t> _availablePins = { 2, 4, 5, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 32, 33 };
const std::vector<PinRole> _allRoles =
{
@@ -55,9 +70,10 @@ private:
static void IRAM_ATTR isrUnlock();
static void IRAM_ATTR isrUnlatch();
std::vector<std::function<void(const GpioAction&)>> _callbacks;
static Gpio* _inst;
static NukiWrapper* _nuki;
static unsigned long _lockedTs;
static unsigned long _debounceTs;
Preferences* _preferences = nullptr;
};

View File

@@ -8,11 +8,12 @@
NukiWrapper* nukiInst;
NukiWrapper::NukiWrapper(const std::string& deviceName, uint32_t id, BleScanner::Scanner* scanner, NetworkLock* network, Preferences* preferences)
NukiWrapper::NukiWrapper(const std::string& deviceName, uint32_t id, BleScanner::Scanner* scanner, NetworkLock* network, Gpio* gpio, Preferences* preferences)
: _deviceName(deviceName),
_bleScanner(scanner),
_nukiLock(deviceName, id),
_network(network),
_gpio(gpio),
_preferences(preferences)
{
nukiInst = this;
@@ -26,6 +27,8 @@ NukiWrapper::NukiWrapper(const std::string& deviceName, uint32_t id, BleScanner:
network->setLockActionReceivedCallback(nukiInst->onLockActionReceivedCallback);
network->setConfigUpdateReceivedCallback(nukiInst->onConfigUpdateReceivedCallback);
network->setKeypadCommandReceivedCallback(nukiInst->onKeypadCommandReceivedCallback);
_gpio->addCallback(NukiWrapper::gpioActionCallback);
}
@@ -307,6 +310,7 @@ void NukiWrapper::updateKeyTurnerState()
_retryLockstateCount = 0;
_network->publishKeyTurnerState(_keyTurnerState, _lastKeyTurnerState);
updateGpioOutputs();
char lockStateStr[20];
lockstateToString(_keyTurnerState.lockState, lockStateStr);
@@ -446,6 +450,22 @@ void NukiWrapper::onKeypadCommandReceivedCallback(const char *command, const uin
nukiInst->onKeypadCommandReceived(command, id, name, code, enabled);
}
void NukiWrapper::gpioActionCallback(const GpioAction &action)
{
switch(action)
{
case GpioAction::Lock:
nukiInst->lock();
break;
case GpioAction::Unlock:
nukiInst->unlock();
break;
case GpioAction::Unlatch:
nukiInst->unlatch();
break;
}
}
void NukiWrapper::onConfigUpdateReceived(const char *topic, const char *value)
{
if(strcmp(topic, mqtt_topic_config_button_enabled) == 0)
@@ -719,3 +739,26 @@ void NukiWrapper::disableWatchdog()
{
_restartBeaconTimeout = -1;
}
void NukiWrapper::updateGpioOutputs()
{
using namespace NukiLock;
const auto& pinConfiguration = _gpio->pinConfiguration();
const LockState& lockState = _keyTurnerState.lockState;
for(const auto& entry : pinConfiguration)
{
switch(entry.role)
{
case PinRole::OutputHighLocked:
_gpio->setPinOutput(entry.pin, lockState == LockState::Locked || lockState == LockState::Locking ? HIGH : LOW);
break;
case PinRole::OutputHighUnlocked:
_gpio->setPinOutput(entry.pin, lockState == LockState::Locked || lockState == LockState::Locking ? LOW : HIGH);
break;
}
}
}

View File

@@ -5,11 +5,12 @@
#include "NukiDataTypes.h"
#include "BleScanner.h"
#include "NukiLock.h"
#include "Gpio.h"
class NukiWrapper : public Nuki::SmartlockEventHandler
{
public:
NukiWrapper(const std::string& deviceName, uint32_t id, BleScanner::Scanner* scanner, NetworkLock* network, Preferences* preferences);
NukiWrapper(const std::string& deviceName, uint32_t id, BleScanner::Scanner* scanner, NetworkLock* network, Gpio* gpio, Preferences* preferences);
virtual ~NukiWrapper();
void initialize(const bool& firstStart);
@@ -42,6 +43,8 @@ private:
static bool onLockActionReceivedCallback(const char* value);
static void onConfigUpdateReceivedCallback(const char* topic, const char* value);
static void onKeypadCommandReceivedCallback(const char* command, const uint& id, const String& name, const String& code, const int& enabled);
static void gpioActionCallback(const GpioAction& action);
void onConfigUpdateReceived(const char* topic, const char* value);
void onKeypadCommandReceived(const char* command, const uint& id, const String& name, const String& code, const int& enabled);
@@ -52,6 +55,8 @@ private:
void updateKeypad();
void postponeBleWatchdog();
void updateGpioOutputs();
void readConfig();
void readAdvancedConfig();
@@ -63,8 +68,9 @@ private:
std::string _deviceName;
NukiLock::NukiLock _nukiLock;
BleScanner::Scanner* _bleScanner;
NetworkLock* _network;
BleScanner::Scanner* _bleScanner = nullptr;
NetworkLock* _network = nullptr;
Gpio* _gpio = nullptr;
Preferences* _preferences;
int _intervalLockstate = 0; // seconds
int _intervalBattery = 0; // seconds

View File

@@ -208,17 +208,19 @@ void setup()
bleScanner->initialize("NukiHub");
bleScanner->setScanDuration(10);
Log->println(lockEnabled ? F("NUKI Lock enabled") : F("NUKI Lock disabled"));
if(lockEnabled)
{
nuki = new NukiWrapper("NukiHub", deviceId, bleScanner, networkLock, preferences);
nuki->initialize(firstStart);
gpio = new Gpio(preferences, nuki);
gpio = new Gpio(preferences);
String gpioDesc;
gpio->getConfigurationText(gpioDesc, gpio->pinConfiguration());
Serial.print(gpioDesc.c_str());
Log->println(lockEnabled ? F("NUKI Lock enabled") : F("NUKI Lock disabled"));
if(lockEnabled)
{
nuki = new NukiWrapper("NukiHub", deviceId, bleScanner, networkLock, gpio, preferences);
nuki->initialize(firstStart);
// if(preferences->getBool(preference_gpio_locking_enabled))
// {
// Gpio::init(nuki);