Files
ESPEasy/src/_P009_MCP.ino
T

235 lines
7.0 KiB
Arduino

#include "_Plugin_Helper.h"
#ifdef USES_P009
# include "src/DataStructs/PinMode.h"
# include "src/ESPEasyCore/ESPEasyGPIO.h"
# include "src/Helpers/_Plugin_Helper_webform.h"
# include "src/PluginStructs/P009_data_struct.h"
// #######################################################################################################
// #################################### Plugin 009: MCP23017 input #######################################
// #######################################################################################################
# define PLUGIN_009
# define PLUGIN_ID_009 9
# define PLUGIN_NAME_009 "Switch input - MCP23017"
# define PLUGIN_VALUENAME1_009 "State"
boolean Plugin_009(uint8_t function, struct EventStruct *event, String& string)
{
boolean success = false;
// static int8_t switchstate[TASKS_MAX];
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
auto& dev = Device[++deviceCount];
dev.Number = PLUGIN_ID_009;
dev.Type = DEVICE_TYPE_I2C;
dev.VType = Sensor_VType::SENSOR_TYPE_SWITCH;
dev.InverseLogicOption = true;
dev.ValueCount = 1;
dev.SendDataOption = true;
dev.TimerOption = true;
dev.TimerOptional = true;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_009);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_009));
break;
}
case PLUGIN_I2C_HAS_ADDRESS:
case PLUGIN_WEBFORM_SHOW_I2C_PARAMS:
{
const uint8_t i2cAddressValues[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27 };
if (function == PLUGIN_WEBFORM_SHOW_I2C_PARAMS) {
String portNames[16];
int portValues[16];
const uint8_t unit = (CONFIG_PORT - 1) / 16;
const uint8_t port = CONFIG_PORT - (unit * 16);
const uint8_t address = 0x20 + unit;
for (uint8_t x = 0; x < 16; ++x) {
portValues[x] = x + 1;
portNames[x] = 'P';
portNames[x] += (x < 8 ? 'A' : 'B');
portNames[x] += (x < 8 ? x : x - 8);
}
addFormSelectorI2C(F("pi2c"), 8, i2cAddressValues, address);
const FormSelectorOptions selector(16, portNames, portValues);
selector.addFormSelector(F("Port"), F("pport"), port);
} else {
success = intArrayContains(8, i2cAddressValues, event->Par1);
}
break;
}
# if FEATURE_I2C_GET_ADDRESS
case PLUGIN_I2C_GET_ADDRESS:
{
event->Par1 = P009_data_struct::getI2C_address(event);
success = true;
break;
}
# endif // if FEATURE_I2C_GET_ADDRESS
case PLUGIN_WEBFORM_LOAD:
{
// @giig1967g: set current task value for taking actions after changes
const uint32_t key = createKey(PLUGIN_MCP, CONFIG_PORT);
auto it = globalMapPortStatus.find(key);
if (it != globalMapPortStatus.end()) {
it->second.previousTask = event->TaskIndex;
}
SwitchWebformLoad(
P009_BOOTSTATE,
P009_DEBOUNCE,
P009_DOUBLECLICK,
P009_DC_MAX_INT,
P009_LONGPRESS,
P009_LP_MIN_INT,
P009_SAFE_BTN);
# if FEATURE_MQTT_DISCOVER && FEATURE_MQTT_DEVICECLASS
addFormSelector_binarySensorDeviceClass(F("MQTT Device class"),
F("devcls"),
P009_MQTT_DEVICECLASS);
# endif // if FEATURE_MQTT_DISCOVER && FEATURE_MQTT_DEVICECLASS
success = true;
break;
}
case PLUGIN_WEBFORM_SAVE:
{
uint8_t i2c = getFormItemInt(F("pi2c"));
uint8_t port = getFormItemInt(F("pport"));
CONFIG_PORT = (((i2c - 0x20) << 4) + port);
SwitchWebformSave(
event->TaskIndex,
PLUGIN_MCP,
P009_BOOTSTATE,
P009_DEBOUNCE,
P009_DOUBLECLICK,
P009_DC_MAX_INT,
P009_LONGPRESS,
P009_LP_MIN_INT,
P009_SAFE_BTN);
# if FEATURE_MQTT_DISCOVER && FEATURE_MQTT_DEVICECLASS
P009_MQTT_DEVICECLASS = getFormItemInt(F("devcls"));
# endif // if FEATURE_MQTT_DISCOVER && FEATURE_MQTT_DEVICECLASS
success = true;
break;
}
# if FEATURE_MQTT_DISCOVER
case PLUGIN_GET_DISCOVERY_VTYPES:
success = getDiscoveryVType(event, Settings.TaskDevicePin1Inversed[event->TaskIndex]
? Plugin_QueryVType_BinarySensorInv
: Plugin_QueryVType_BinarySensor, 255, event->Par5);
# if FEATURE_MQTT_DEVICECLASS
string = MQTT_binary_deviceClassName(P009_MQTT_DEVICECLASS); // User selected device_cLass/dev_cls value
# endif // if FEATURE_MQTT_DEVICECLASS
break;
# endif // if FEATURE_MQTT_DISCOVER
case PLUGIN_INIT:
{
// apply INIT only if PIN is in range. Do not start INIT if pin not set in the device page.
if (CONFIG_PORT >= 0)
{
success = initPluginTaskData(event->TaskIndex, new (std::nothrow) P009_data_struct(event));
}
break;
}
case PLUGIN_TEN_PER_SECOND:
{
P009_data_struct *P009_data =
static_cast<P009_data_struct *>(getPluginTaskData(event->TaskIndex));
if (nullptr != P009_data)
{
P009_data->tenPerSecond(event);
success = true;
}
break;
}
case PLUGIN_READ:
{
// We do not actually read the pin state as this is already done 10x/second
// Instead we just send the last known state stored in Uservar
#ifndef BUILD_NO_DEBUG
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
addLog(LOG_LEVEL_INFO,
strformat(F("MCP : Port=%d State=%d"), CONFIG_PORT, UserVar[event->BaseVarIndex]));
}
#endif
success = true;
break;
}
case PLUGIN_REQUEST:
{
// parseString(string, 1) = device
// parseString(string, 2) = command
// parseString(string, 3) = gpio number
// returns pin value using syntax: [plugin#mcpgpio#pinstate#xx]
if ((string.length() >= 16) && string.substring(0, 16).equalsIgnoreCase(F("mcpgpio,pinstate")))
{
int32_t par1;
if (validIntFromString(parseString(string, 3), par1)) {
string = GPIO_MCP_Read(par1);
}
success = true;
}
break;
}
case PLUGIN_TASKTIMER_IN:
case PLUGIN_DEVICETIMER_IN:
{
Scheduler.clearGPIOTimer(PLUGIN_MCP, event->Par1);
GPIO_MCP_Write(event->Par1, event->Par2);
// WARNING: operator [] creates an entry in the map if key does not exist
const uint32_t key = createKey(PLUGIN_MCP, event->Par1);
portStatusStruct tempStatus = globalMapPortStatus[key];
tempStatus.state = event->Par2;
tempStatus.mode = PIN_MODE_OUTPUT;
tempStatus.forceMonitor = (tempStatus.monitor) ? 1 : 0; // added to send event for longpulse command
savePortStatus(key, tempStatus);
break;
}
}
return success;
}
#endif // USES_P009