Browse Source

hw: Implement support for ProDino WIFI (#2269)

- implement mcp23s08
- support mcp pins in relays and buttons
- add hardware profile for ProDino WiFi

Co-authored-by: dpeddi <dpeddi@gmail.com>
Co-authored-by: Maxim Prokhorov <prokhorov.max@outlook.com>
mcspr-patch-1
dpeddi 4 years ago
committed by GitHub
parent
commit
547f52fe79
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 420 additions and 61 deletions
  1. +2
    -0
      code/espurna/board.cpp
  2. +26
    -9
      code/espurna/button.cpp
  3. +1
    -0
      code/espurna/config/arduino.h
  4. +9
    -0
      code/espurna/config/general.h
  5. +45
    -0
      code/espurna/config/hardware.h
  6. +2
    -0
      code/espurna/config/types.h
  7. +1
    -1
      code/espurna/domoticz.cpp
  8. +13
    -9
      code/espurna/libs/BasePin.h
  9. +6
    -0
      code/espurna/main.cpp
  10. +184
    -0
      code/espurna/mcp23s08.cpp
  11. +46
    -0
      code/espurna/mcp23s08.h
  12. +79
    -41
      code/espurna/relay.cpp
  13. +1
    -1
      code/espurna/relay.h
  14. +5
    -0
      code/platformio.ini

+ 2
- 0
code/espurna/board.cpp View File

@ -681,6 +681,8 @@ int getBoardId() {
return 157; return 157;
#elif defined(GENERIC_AG_L4_V3) #elif defined(GENERIC_AG_L4_V3)
return 158; return 158;
#elif defined(PRODINO_WIFI)
return 159;
#else #else
return -1; // CUSTOM return -1; // CUSTOM
#endif #endif


+ 26
- 9
code/espurna/button.cpp View File

@ -21,6 +21,7 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "relay.h" #include "relay.h"
#include "light.h" #include "light.h"
#include "ws.h" #include "ws.h"
#include "mcp23s08.h"
#include "button_config.h" #include "button_config.h"
@ -282,7 +283,8 @@ void _buttonWebSocketOnVisible(JsonObject& root) {
} }
#if (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_ITEAD_SONOFF_DUAL) || \ #if (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_ITEAD_SONOFF_DUAL) || \
(BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL)
(BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL) || \
(BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_MCP23S08)
void _buttonWebSocketOnConnected(JsonObject& root) { void _buttonWebSocketOnConnected(JsonObject& root) {
root["btnRepDel"] = getSetting("btnRepDel", _buttonRepeatDelay()); root["btnRepDel"] = getSetting("btnRepDel", _buttonRepeatDelay());
@ -623,7 +625,8 @@ void _buttonLoopGeneric() {
void buttonLoop() { void buttonLoop() {
#if BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_GENERIC
#if (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_GENERIC) || \
(BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_MCP23S08)
_buttonLoopGeneric(); _buttonLoopGeneric();
#elif (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_ITEAD_SONOFF_DUAL) || \ #elif (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_ITEAD_SONOFF_DUAL) || \
(BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL) (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL)
@ -642,7 +645,6 @@ void buttonSetup() {
// Special hardware cases // Special hardware cases
#if (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_ITEAD_SONOFF_DUAL) || \ #if (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_ITEAD_SONOFF_DUAL) || \
(BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL) (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL)
size_t buttons = 0; size_t buttons = 0;
#if BUTTON1_RELAY != RELAY_NONE #if BUTTON1_RELAY != RELAY_NONE
++buttons; ++buttons;
@ -677,11 +679,13 @@ void buttonSetup() {
actions, actions,
delays delays
); );
} }
// Generic GPIO input handlers // Generic GPIO input handlers
#elif BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_GENERIC
#elif (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_GENERIC) || \
(BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_MCP23S08)
size_t buttons = 0; size_t buttons = 0;
@ -712,11 +716,25 @@ void buttonSetup() {
_buttons.reserve(buttons); _buttons.reserve(buttons);
// TODO: allow to change gpio pin type based on config?
#if (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_GENERIC)
using gpio_type = GpioPin;
#elif (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_MCP23S08)
using gpio_type = McpGpioPin;
#endif
for (unsigned char index = 0; index < ButtonsMax; ++index) { for (unsigned char index = 0; index < ButtonsMax; ++index) {
const auto pin = getSetting({"btnGPIO", index}, _buttonPin(index)); const auto pin = getSetting({"btnGPIO", index}, _buttonPin(index));
if (!gpioValid(pin)) {
break;
}
#if (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_GENERIC)
if (!gpioValid(pin)) {
break;
}
#elif (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_MCP23S08)
if (!mcpGpioValid(pin)) {
break;
}
#endif
const auto relayID = getSetting({"btnRelay", index}, _buttonRelay(index)); const auto relayID = getSetting({"btnRelay", index}, _buttonRelay(index));
// TODO: compatibility proxy, fetch global key before indexed // TODO: compatibility proxy, fetch global key before indexed
@ -738,9 +756,8 @@ void buttonSetup() {
const auto config = _buttonConfig(index); const auto config = _buttonConfig(index);
// TODO: allow to change GpioPin to something else based on config?
_buttons.emplace_back( _buttons.emplace_back(
std::make_shared<GpioPin>(pin), config,
std::make_shared<gpio_type>(pin), config,
relayID, actions, delays relayID, actions, delays
); );
} }


+ 1
- 0
code/espurna/config/arduino.h View File

@ -144,6 +144,7 @@
//#define OUKITEL_P1 //#define OUKITEL_P1
//#define PHYX_ESP12_RGB //#define PHYX_ESP12_RGB
//#define PILOTAK_ESP_DIN_V1 //#define PILOTAK_ESP_DIN_V1
//#define PRODINO_WIFI
//#define PSH_RGBW_CONTROLLER //#define PSH_RGBW_CONTROLLER
//#define PSH_WIFI_PLUG //#define PSH_WIFI_PLUG
//#define PSH_WIFI_SENSOR //#define PSH_WIFI_SENSOR


+ 9
- 0
code/espurna/config/general.h View File

@ -405,6 +405,7 @@
// BUTTON_EVENTS_SOURCE_GENERIC - GPIOs (virtual or real) // BUTTON_EVENTS_SOURCE_GENERIC - GPIOs (virtual or real)
// BUTTON_EVENTS_SOURCE_SONOFF_DUAL - hardware specific, drive buttons through serial connection // BUTTON_EVENTS_SOURCE_SONOFF_DUAL - hardware specific, drive buttons through serial connection
// BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL - similar to Itead Sonoff Dual, hardware specific // BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL - similar to Itead Sonoff Dual, hardware specific
// BUTTON_EVENTS_SOURCE_MCP23S08 - activate virtual button connected to gpio expander
#endif #endif
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -1776,6 +1777,14 @@
#define TUYA_SERIAL Serial #define TUYA_SERIAL Serial
#endif #endif
//--------------------------------------------------------------------------------
// Support expander MCP23S08
//--------------------------------------------------------------------------------
#ifndef MCP23S08_SUPPORT
#define MCP23S08_SUPPORT 0
#endif
// ============================================================================= // =============================================================================
// Configuration helpers // Configuration helpers
// ============================================================================= // =============================================================================


+ 45
- 0
code/espurna/config/hardware.h View File

@ -4814,6 +4814,51 @@
#define LED1_PIN 1 #define LED1_PIN 1
#define LED1_PIN_INVERSE 1 #define LED1_PIN_INVERSE 1
// -----------------------------------------------------------------------------
// Prodino WIFI
// https://kmpelectronics.eu/products/prodino-wifi-v1/
// -------------------------------------
#elif defined(PRODINO_WIFI)
// Info
#define MANUFACTURER "PRODINO"
#define DEVICE "WIFI"
// MCP23S08
#define MCP23S08_SUPPORT 1
// Relays
#define RELAY_PROVIDER RELAY_PROVIDER_MCP23S08
#define RELAY1_PIN 4
#define RELAY2_PIN 5
#define RELAY3_PIN 6
#define RELAY4_PIN 7
// Buttons
#define BUTTON1_CONFIG BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
#define BUTTON1_PIN 0
#define BUTTON2_CONFIG BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
#define BUTTON2_PIN 1
#define BUTTON3_CONFIG BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
#define BUTTON3_PIN 2
#define BUTTON4_CONFIG BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH
#define BUTTON4_PIN 3
#define BUTTON1_RELAY 1
#define BUTTON2_RELAY 2
#define BUTTON3_RELAY 3
#define BUTTON4_RELAY 4
#define BUTTON_EVENTS_SOURCE BUTTON_EVENTS_SOURCE_MCP23S08
// LEDs
#define LED1_PIN 2
#define LED1_PIN_INVERSE 1
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
#else #else


+ 2
- 0
code/espurna/config/types.h View File

@ -61,6 +61,7 @@
#define BUTTON_EVENTS_SOURCE_GENERIC 0 #define BUTTON_EVENTS_SOURCE_GENERIC 0
#define BUTTON_EVENTS_SOURCE_ITEAD_SONOFF_DUAL 1 #define BUTTON_EVENTS_SOURCE_ITEAD_SONOFF_DUAL 1
#define BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL 2 #define BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL 2
#define BUTTON_EVENTS_SOURCE_MCP23S08 3
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// ENCODER // ENCODER
@ -100,6 +101,7 @@
#define RELAY_PROVIDER_LIGHT 2 #define RELAY_PROVIDER_LIGHT 2
#define RELAY_PROVIDER_RFBRIDGE 3 #define RELAY_PROVIDER_RFBRIDGE 3
#define RELAY_PROVIDER_STM 4 #define RELAY_PROVIDER_STM 4
#define RELAY_PROVIDER_MCP23S08 5
#define RELAY_GROUP_SYNC_NORMAL 0 #define RELAY_GROUP_SYNC_NORMAL 0
#define RELAY_GROUP_SYNC_INVERSE 1 #define RELAY_GROUP_SYNC_INVERSE 1


+ 1
- 1
code/espurna/domoticz.cpp View File

@ -19,7 +19,7 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "ws.h" #include "ws.h"
bool _dcz_enabled = false; bool _dcz_enabled = false;
std::bitset<RELAYS_MAX> _dcz_relay_state;
std::bitset<RelaysMax> _dcz_relay_state;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Private methods // Private methods


+ 13
- 9
code/espurna/libs/BasePin.h View File

@ -9,17 +9,21 @@ Copyright (C) 2020 by Maxim Prokhorov <prokhorov dot max at outlook dot com>
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include "config/types.h"
// base interface for generic pin handler. // base interface for generic pin handler.
class BasePin {
public:
BasePin(unsigned char pin) :
pin(pin)
{}
struct BasePin {
BasePin(unsigned char pin) :
pin(pin)
{}
virtual void pinMode(int8_t mode) = 0;
virtual void digitalWrite(int8_t val) = 0;
virtual int digitalRead() = 0;
virtual operator bool() {
return GPIO_NONE != pin;
}
const unsigned char pin;
virtual void pinMode(int8_t mode) = 0;
virtual void digitalWrite(int8_t val) = 0;
virtual int digitalRead() = 0;
const unsigned char pin;
}; };

+ 6
- 0
code/espurna/main.cpp View File

@ -60,6 +60,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "uartmqtt.h" #include "uartmqtt.h"
#include "web.h" #include "web.h"
#include "ws.h" #include "ws.h"
#include "mcp23s08.h"
std::vector<void_callback_f> _loop_callbacks; std::vector<void_callback_f> _loop_callbacks;
std::vector<void_callback_f> _reload_callbacks; std::vector<void_callback_f> _reload_callbacks;
@ -193,6 +194,11 @@ void setup() {
apiSetup(); apiSetup();
#endif #endif
// Hardware GPIO expander, needs to be available for modules down below
#if MCP23S08_SUPPORT
MCP23S08Setup();
#endif
// lightSetup must be called before relaySetup // lightSetup must be called before relaySetup
#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE
lightSetup(); lightSetup();


+ 184
- 0
code/espurna/mcp23s08.cpp View File

@ -0,0 +1,184 @@
/*
MCP23S08 MODULE
Copyright (C) 2020 by Eddi De Pieri <eddi at depieri dot com>
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016 Plamen Kovandjiev <p.kovandiev@kmpelectronics.eu> & Dimitar Antonov <d.antonov@kmpelectronics.eu>
*/
#include "mcp23s08.h"
#if MCP23S08_SUPPORT
#include <SPI.h>
#include <bitset>
// TODO: check if this needed for SPI operation
#define MCP23S08_CS_PIN 15
// Known commands
#define READ_CMD 0x41
#define WRITE_CMD 0x40
// Registers
#define IODIR 0x00
#define IPOL 0x01
#define GPINTEN 0x02
#define DEFVAL 0x03
#define INTCON 0x04
#define IOCON 0x05
#define GPPU 0x06
#define INTF 0x07
#define INTCAP 0x08
#define GPIO 0x09
#define OLAT 0x0A
static uint8_t _mcp23s08TxData[16] __attribute__((aligned(4)));
static uint8_t _mcp23s08RxData[16] __attribute__((aligned(4)));
McpGpioPin::McpGpioPin(unsigned char pin) :
BasePin(pin)
{}
inline void McpGpioPin::pinMode(int8_t mode) {
::MCP23S08SetDirection(this->pin, mode);
}
inline void McpGpioPin::digitalWrite(int8_t val) {
::MCP23S08SetPin(this->pin, val);
}
inline int McpGpioPin::digitalRead() {
return ::MCP23S08GetPin(this->pin);
}
void MCP23S08Setup()
{
DEBUG_MSG_P(PSTR("[MCP23S08] Initialize SPI bus\n"));
// Expander SPI settings
SPI.begin();
SPI.setHwCs(true);
SPI.setFrequency(1000000);
SPI.setDataMode(SPI_MODE0);
pinMode(MCP23S08_CS_PIN, OUTPUT);
digitalWrite(MCP23S08_CS_PIN, HIGH);
}
/**
* @brief Set a expander MCP23S08 the pin direction.
*
* @param pinNumber Pin number for set.
* @param mode direction mode. 0 - INPUT, 1 - OUTPUT.
*
* @return void
*/
void MCP23S08SetDirection(uint8_t pinNumber, uint8_t mode)
{
uint8_t registerData = MCP23S08ReadRegister(IODIR);
if (INPUT == mode)
{
registerData |= (1 << pinNumber);
}
else
{
registerData &= ~(1 << pinNumber);
}
MCP23S08WriteRegister(IODIR, registerData);
}
/**
* @brief Read an expander MCP23S08 a register.
*
* @param address A register address.
*
* @return The data from the register.
*/
uint8_t MCP23S08ReadRegister(uint8_t address)
{
_mcp23s08TxData[0] = READ_CMD;
_mcp23s08TxData[1] = address;
digitalWrite(MCP23S08_CS_PIN, LOW);
SPI.transferBytes(_mcp23s08TxData, _mcp23s08RxData, 3);
digitalWrite(MCP23S08_CS_PIN, HIGH);
return _mcp23s08RxData[2];
}
/**
* @brief Write data in expander MCP23S08 register.
*
* @param address A register address.
* @param data A byte for write.
*
* @return void.
*/
void MCP23S08WriteRegister(uint8_t address, uint8_t data)
{
_mcp23s08TxData[0] = WRITE_CMD;
_mcp23s08TxData[1] = address;
_mcp23s08TxData[2] = data;
digitalWrite(MCP23S08_CS_PIN, LOW);
SPI.transferBytes(_mcp23s08TxData, _mcp23s08RxData, 3);
digitalWrite(MCP23S08_CS_PIN, HIGH);
}
/**
* @brief Set expander MCP23S08 pin state.
*
* @param pinNumber The number of pin to be set.
* @param state The pin state, true - 1, false - 0.
*
* @return void
*/
void MCP23S08SetPin(uint8_t pinNumber, bool state)
{
uint8_t registerData = MCP23S08ReadRegister(OLAT);
if (state)
{
registerData |= (1 << pinNumber);
}
else
{
registerData &= ~(1 << pinNumber);
}
MCP23S08WriteRegister(OLAT, registerData);
}
/**
* @brief Get MCP23S08 pin state.
*
* @param pinNumber The number of pin to get.
*
* @return State true - 1, false - 0.
*/
bool MCP23S08GetPin(uint8_t pinNumber)
{
uint8_t registerData = MCP23S08ReadRegister(GPIO);
return registerData & (1 << pinNumber);
}
/**
* @brief Ensure pin number is valid.
*
* @param pinNumber The number of pin to be get.
*
* @return State true - 1, false - 0.
*/
bool mcpGpioValid(unsigned char gpio)
{
return gpio < McpGpioPins;
}
#endif // MCP23S08_SUPPORT

+ 46
- 0
code/espurna/mcp23s08.h View File

@ -0,0 +1,46 @@
/*
MCP23S08 MODULE
Copyright (C) 2020-2020 by Eddi De Pieri <eddi at depieri dot com>
Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
Copyright (C) 2016-2017 Plamen Kovandjiev <p.kovandiev@kmpelectronics.eu> & Dimitar Antonov <d.antonov@kmpelectronics.eu>
*/
#pragma once
#ifndef MCP23S08_H
#define MCP23S08_H
#include "espurna.h"
#include "libs/BasePin.h"
#if MCP23S08_SUPPORT
constexpr size_t McpGpioPins = 8;
// real hardware pin
class McpGpioPin final : public BasePin {
public:
McpGpioPin(unsigned char pin);
void pinMode(int8_t mode);
void digitalWrite(int8_t val);
int digitalRead();
};
void MCP23S08Setup();
uint8_t MCP23S08ReadRegister(uint8_t address);
void MCP23S08WriteRegister(uint8_t address, uint8_t data);
void MCP23S08SetDirection(uint8_t pinNumber, uint8_t mode);
void MCP23S08SetPin(uint8_t pinNumber, bool state);
bool MCP23S08GetPin(uint8_t pinNumber);
bool mcpGpioValid(unsigned char gpio);
#endif // MCP23S08_SUPPORT == 1
#endif

+ 79
- 41
code/espurna/relay.cpp View File

@ -28,17 +28,32 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include "tuya.h" #include "tuya.h"
#include "utils.h" #include "utils.h"
#include "ws.h" #include "ws.h"
#include "mcp23s08.h"
#include "libs/BasePin.h"
#include "relay_config.h" #include "relay_config.h"
struct DummyPin final : public BasePin {
DummyPin(unsigned char pin) :
BasePin(pin)
{}
void pinMode(int8_t) override {}
void digitalWrite(int8_t) override {}
int digitalRead() override { return 0; }
};
struct relay_t { struct relay_t {
// Default to dummy (virtual) relay configuration
using pin_type = std::unique_ptr<BasePin>;
// Default to empty relay configuration, as we allow switches to exist without real GPIOs
relay_t(unsigned char pin, unsigned char type, unsigned char reset_pin) :
pin(pin),
relay_t(pin_type&& pin, unsigned char type, pin_type&& reset_pin) :
pin(std::move(pin)),
reset_pin(std::move(reset_pin)),
type(type), type(type),
reset_pin(reset_pin),
delay_on(0), delay_on(0),
delay_off(0), delay_off(0),
pulse(RELAY_PULSE_NONE), pulse(RELAY_PULSE_NONE),
@ -55,20 +70,13 @@ struct relay_t {
{} {}
relay_t() : relay_t() :
relay_t(GPIO_NONE, RELAY_TYPE_NORMAL, GPIO_NONE)
relay_t(std::make_unique<DummyPin>(GPIO_NONE), RELAY_TYPE_NORMAL, std::make_unique<DummyPin>(GPIO_NONE))
{} {}
// ... unless there are pre-configured values
pin_type pin; // GPIO pin for the relay
pin_type reset_pin; // GPIO to reset the relay if RELAY_TYPE_LATCHED
relay_t(unsigned char id) :
relay_t(_relayPin(id), _relayType(id), _relayResetPin(id))
{}
// Configuration variables
unsigned char pin; // GPIO pin for the relay
unsigned char type; // RELAY_TYPE_NORMAL, RELAY_TYPE_INVERSE, RELAY_TYPE_LATCHED or RELAY_TYPE_LATCHED_INVERSE unsigned char type; // RELAY_TYPE_NORMAL, RELAY_TYPE_INVERSE, RELAY_TYPE_LATCHED or RELAY_TYPE_LATCHED_INVERSE
unsigned char reset_pin; // GPIO to reset the relay if RELAY_TYPE_LATCHED
unsigned long delay_on; // Delay to turn relay ON unsigned long delay_on; // Delay to turn relay ON
unsigned long delay_off; // Delay to turn relay OFF unsigned long delay_off; // Delay to turn relay OFF
unsigned char pulse; // RELAY_PULSE_NONE, RELAY_PULSE_OFF or RELAY_PULSE_ON unsigned char pulse; // RELAY_PULSE_NONE, RELAY_PULSE_OFF or RELAY_PULSE_ON
@ -300,27 +308,33 @@ void _relayProviderStatus(unsigned char id, bool status) {
#endif #endif
#if (RELAY_PROVIDER == RELAY_PROVIDER_RELAY) || (RELAY_PROVIDER == RELAY_PROVIDER_LIGHT)
#if (RELAY_PROVIDER == RELAY_PROVIDER_RELAY) || \
(RELAY_PROVIDER == RELAY_PROVIDER_LIGHT) || \
(RELAY_PROVIDER == RELAY_PROVIDER_MCP23S08)
// If this is a light, all dummy relays have already been processed above // If this is a light, all dummy relays have already been processed above
// we reach here if the user has toggled a physical relay // we reach here if the user has toggled a physical relay
if (_relays[id].type == RELAY_TYPE_NORMAL) { if (_relays[id].type == RELAY_TYPE_NORMAL) {
digitalWrite(_relays[id].pin, status);
_relays[id].pin->digitalWrite(status);
} else if (_relays[id].type == RELAY_TYPE_INVERSE) { } else if (_relays[id].type == RELAY_TYPE_INVERSE) {
digitalWrite(_relays[id].pin, !status);
_relays[id].pin->digitalWrite(!status);
} else if (_relays[id].type == RELAY_TYPE_LATCHED || _relays[id].type == RELAY_TYPE_LATCHED_INVERSE) { } else if (_relays[id].type == RELAY_TYPE_LATCHED || _relays[id].type == RELAY_TYPE_LATCHED_INVERSE) {
bool pulse = (_relays[id].type == RELAY_TYPE_LATCHED) ? HIGH : LOW; bool pulse = (_relays[id].type == RELAY_TYPE_LATCHED) ? HIGH : LOW;
digitalWrite(_relays[id].pin, !pulse);
if (GPIO_NONE != _relays[id].reset_pin) digitalWrite(_relays[id].reset_pin, !pulse);
if (status || (GPIO_NONE == _relays[id].reset_pin)) {
digitalWrite(_relays[id].pin, pulse);
_relays[id].pin->digitalWrite(!pulse);
if (GPIO_NONE != _relays[id].reset_pin->pin) {
_relays[id].reset_pin->digitalWrite(!pulse);
}
if (status || (GPIO_NONE == _relays[id].reset_pin->pin)) {
_relays[id].pin->digitalWrite(pulse);
} else { } else {
digitalWrite(_relays[id].reset_pin, pulse);
_relays[id].reset_pin->digitalWrite(pulse);
} }
nice_delay(RELAY_LATCHING_PULSE); nice_delay(RELAY_LATCHING_PULSE);
digitalWrite(_relays[id].pin, !pulse);
if (GPIO_NONE != _relays[id].reset_pin) digitalWrite(_relays[id].reset_pin, !pulse);
_relays[id].pin->digitalWrite(!pulse);
if (GPIO_NONE != _relays[id].reset_pin->pin) {
_relays[id].reset_pin->digitalWrite(!pulse);
}
} }
#endif #endif
@ -471,7 +485,7 @@ void INLINE _relayMaskRtcmem(const RelayMask& mask) {
_relayMaskRtcmem(mask.as_u32); _relayMaskRtcmem(mask.as_u32);
} }
void INLINE _relayMaskRtcmem(const std::bitset<RELAYS_MAX>& bitset) {
void INLINE _relayMaskRtcmem(const std::bitset<RelaysMax>& bitset) {
_relayMaskRtcmem(bitset.to_ulong()); _relayMaskRtcmem(bitset.to_ulong());
} }
@ -489,7 +503,7 @@ void INLINE _relayMaskSettings(const RelayMask& mask) {
setSetting("relayBootMask", mask.as_string); setSetting("relayBootMask", mask.as_string);
} }
void INLINE _relayMaskSettings(const std::bitset<RELAYS_MAX>& bitset) {
void INLINE _relayMaskSettings(const std::bitset<RelaysMax>& bitset) {
_relayMaskSettings(bitset.to_ulong()); _relayMaskSettings(bitset.to_ulong());
} }
@ -682,9 +696,9 @@ void relaySync(unsigned char id) {
void relaySave(bool eeprom) { void relaySave(bool eeprom) {
const unsigned char count = constrain(relayCount(), 0, RELAYS_MAX);
const unsigned char count = constrain(relayCount(), 0, RelaysMax);
auto statuses = std::bitset<RELAYS_MAX>(0);
auto statuses = std::bitset<RelaysMax>(0);
for (unsigned int id = 0; id < count; ++id) { for (unsigned int id = 0; id < count; ++id) {
statuses.set(id, relayStatus(id)); statuses.set(id, relayStatus(id));
} }
@ -766,7 +780,7 @@ void _relayBoot() {
DEBUG_MSG_P(PSTR("[RELAY] Retrieving mask: %s\n"), stored_mask.as_string.c_str()); DEBUG_MSG_P(PSTR("[RELAY] Retrieving mask: %s\n"), stored_mask.as_string.c_str());
auto mask = std::bitset<RELAYS_MAX>(stored_mask.as_u32);
auto mask = std::bitset<RelaysMax>(stored_mask.as_u32);
// Walk the relays // Walk the relays
unsigned char lock; unsigned char lock;
@ -835,15 +849,17 @@ void _relayConfigure() {
_relays[i].delay_on = getSetting({"relayDelayOn", i}, _relayDelayOn(i)); _relays[i].delay_on = getSetting({"relayDelayOn", i}, _relayDelayOn(i));
_relays[i].delay_off = getSetting({"relayDelayOff", i}, _relayDelayOff(i)); _relays[i].delay_off = getSetting({"relayDelayOff", i}, _relayDelayOff(i));
if (GPIO_NONE == _relays[i].pin) continue;
// make sure pin is valid before continuing with writes
if (!static_cast<bool>(*_relays[i].pin)) continue;
pinMode(_relays[i].pin, OUTPUT);
if (GPIO_NONE != _relays[i].reset_pin) {
pinMode(_relays[i].reset_pin, OUTPUT);
_relays[i].pin->pinMode(OUTPUT);
if (static_cast<bool>(*_relays[i].reset_pin)) {
_relays[i].reset_pin->pinMode(OUTPUT);
} }
if (_relays[i].type == RELAY_TYPE_INVERSE) { if (_relays[i].type == RELAY_TYPE_INVERSE) {
//set to high to block short opening of relay //set to high to block short opening of relay
digitalWrite(_relays[i].pin, HIGH);
_relays[i].pin->digitalWrite(HIGH);
} }
} }
@ -887,9 +903,9 @@ void _relayWebSocketUpdate(JsonObject& root) {
} }
String _relayFriendlyName(unsigned char i) { String _relayFriendlyName(unsigned char i) {
String res = String("GPIO") + String(_relays[i].pin);
String res = String("GPIO") + String(_relays[i].pin->pin);
if (GPIO_NONE == _relays[i].pin) {
if (GPIO_NONE == _relays[i].pin->pin) {
#if (RELAY_PROVIDER == RELAY_PROVIDER_LIGHT) #if (RELAY_PROVIDER == RELAY_PROVIDER_LIGHT)
uint8_t physical = _relays.size() - _relayDummy; uint8_t physical = _relays.size() - _relayDummy;
if (i >= physical) { if (i >= physical) {
@ -942,7 +958,7 @@ void _relayWebSocketSendRelays(JsonObject& root) {
gpio.add(_relayFriendlyName(i)); gpio.add(_relayFriendlyName(i));
type.add(_relays[i].type); type.add(_relays[i].type);
reset.add(_relays[i].reset_pin);
reset.add(_relays[i].reset_pin->pin);
boot.add(getSetting({"relayBoot", i}, RELAY_BOOT_MODE)); boot.add(getSetting({"relayBoot", i}, RELAY_BOOT_MODE));
pulse.add(_relays[i].pulse); pulse.add(_relays[i].pulse);
@ -1401,7 +1417,7 @@ void relaySetupDummy(size_t size, bool reconfigure) {
if (size == _relayDummy) return; if (size == _relayDummy) return;
const size_t new_size = ((_relays.size() - _relayDummy) + size); const size_t new_size = ((_relays.size() - _relayDummy) + size);
if (new_size > RELAYS_MAX) return;
if (new_size > RelaysMax) return;
_relayDummy = size; _relayDummy = size;
_relays.resize(new_size); _relays.resize(new_size);
@ -1418,7 +1434,7 @@ void relaySetupDummy(size_t size, bool reconfigure) {
void _relaySetupAdhoc() { void _relaySetupAdhoc() {
size_t relays = 0;
size_t relays [[gnu::unused]] = 0;
#if RELAY1_PIN != GPIO_NONE #if RELAY1_PIN != GPIO_NONE
++relays; ++relays;
@ -1446,8 +1462,30 @@ void _relaySetupAdhoc() {
#endif #endif
_relays.reserve(relays); _relays.reserve(relays);
for (unsigned char id = 0; id < relays; ++id) {
_relays.emplace_back(id);
#if (RELAY_PROVIDER == RELAY_PROVIDER_RELAY) || (RELAY_PROVIDER == RELAY_PROVIDER_LIGHT)
using gpio_type = GpioPin;
#elif (RELAY_PROVIDER == RELAY_PROVIDER_MCP23S08)
using gpio_type = McpGpioPin;
#endif
for (unsigned char id = 0; id < RelaysMax; ++id) {
const auto pin = _relayPin(id);
#if (RELAY_PROVIDER == RELAY_PROVIDER_RELAY) || (RELAY_PROVIDER == RELAY_PROVIDER_LIGHT)
if (!gpioValid(pin)) {
break;
}
#elif (RELAY_PROVIDER == RELAY_PROVIDER_MCP23S08)
if (!mcpGpioValid(pin)) {
break;
}
#endif
_relays.emplace_back(
std::make_unique<gpio_type>(_relayPin(id)),
_relayType(id),
std::make_unique<gpio_type>(_relayResetPin(id))
);
} }
} }


+ 1
- 1
code/espurna/relay.h View File

@ -13,7 +13,7 @@ Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
#include <bitset> #include <bitset>
constexpr size_t RELAYS_MAX = 32;
constexpr size_t RelaysMax = 32;
PayloadStatus relayParsePayload(const char * payload); PayloadStatus relayParsePayload(const char * payload);


+ 5
- 0
code/platformio.ini View File

@ -1064,3 +1064,8 @@ src_build_flags = -DARLEC_PC190HA
[env:arlec-pb89ha] [env:arlec-pb89ha]
extends = env:esp8266-1m-base extends = env:esp8266-1m-base
src_build_flags = -DARLEC_PB89HA src_build_flags = -DARLEC_PB89HA
[env:prodino-wifi]
extends = env:esp8266-2m-base
src_build_flags = -DPRODINO_WIFI -DNOWSAUTH

Loading…
Cancel
Save