mirror of
https://github.com/anklimov/lighthub
synced 2025-12-06 11:49:51 +03:00
PID+PWM relay thermostat, init from flash fixed
This commit is contained in:
@@ -19,6 +19,6 @@ int abstractOut::isActive()
|
|||||||
|
|
||||||
int abstractOut::Setup()
|
int abstractOut::Setup()
|
||||||
{
|
{
|
||||||
if (item) item->setCmd(CMD_OFF);
|
if (item && (item->getCmd()==-1)) item->setCmd(CMD_OFF);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -50,6 +50,7 @@ e-mail anklimov@gmail.com
|
|||||||
#include "modules/out_pid.h"
|
#include "modules/out_pid.h"
|
||||||
#include "modules/out_multivent.h"
|
#include "modules/out_multivent.h"
|
||||||
#include "modules/out_uartbridge.h"
|
#include "modules/out_uartbridge.h"
|
||||||
|
#include "modules/out_relay.h"
|
||||||
|
|
||||||
#ifdef ELEVATOR_ENABLE
|
#ifdef ELEVATOR_ENABLE
|
||||||
#include "modules/out_elevator.h"
|
#include "modules/out_elevator.h"
|
||||||
@@ -147,48 +148,48 @@ void Item::Parse() {
|
|||||||
case CH_DIMMER:
|
case CH_DIMMER:
|
||||||
case CH_RGBWW:
|
case CH_RGBWW:
|
||||||
driver = new out_dmx (this);
|
driver = new out_dmx (this);
|
||||||
// debugSerial<<F("DMX driver created")<<endl;
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifndef SPILED_DISABLE
|
#ifndef SPILED_DISABLE
|
||||||
case CH_SPILED:
|
case CH_SPILED:
|
||||||
driver = new out_SPILed (this);
|
driver = new out_SPILed (this);
|
||||||
// debugSerial<<F("SPILED driver created")<<endl;
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef AC_DISABLE
|
#ifndef AC_DISABLE
|
||||||
case CH_AC:
|
case CH_AC:
|
||||||
driver = new out_AC (this);
|
driver = new out_AC (this);
|
||||||
// debugSerial<<F("AC driver created")<<endl;
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MOTOR_DISABLE
|
#ifndef MOTOR_DISABLE
|
||||||
case CH_MOTOR:
|
case CH_MOTOR:
|
||||||
driver = new out_Motor (this);
|
driver = new out_Motor (this);
|
||||||
// debugSerial<<F("AC driver created")<<endl;
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MBUS_DISABLE
|
#ifndef MBUS_DISABLE
|
||||||
case CH_MBUS:
|
case CH_MBUS:
|
||||||
driver = new out_Modbus (this);
|
driver = new out_Modbus (this);
|
||||||
// debugSerial<<F("AC driver created")<<endl;
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PID_DISABLE
|
#ifndef PID_DISABLE
|
||||||
case CH_PID:
|
case CH_PID:
|
||||||
driver = new out_pid (this);
|
driver = new out_pid (this);
|
||||||
// debugSerial<<F("AC driver created")<<endl;
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef RELAY_DISABLE
|
||||||
|
case CH_RELAYX:
|
||||||
|
driver = new out_relay (this);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MULTIVENT_DISABLE
|
#ifndef MULTIVENT_DISABLE
|
||||||
case CH_MULTIVENT:
|
case CH_MULTIVENT:
|
||||||
driver = new out_Multivent (this);
|
driver = new out_Multivent (this);
|
||||||
// debugSerial<<F("AC driver created")<<endl;
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -217,7 +218,11 @@ boolean Item::Setup()
|
|||||||
if (driver)
|
if (driver)
|
||||||
{
|
{
|
||||||
if (driver->Status()) driver->Stop();
|
if (driver->Status()) driver->Stop();
|
||||||
driver->Setup();
|
if (driver->Setup())
|
||||||
|
{
|
||||||
|
if (getCmd()) setFlag(SEND_COMMAND);
|
||||||
|
if (itemVal) setFlag(SEND_PARAMETERS);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else return false;
|
else return false;
|
||||||
@@ -237,7 +242,6 @@ Item::~Item()
|
|||||||
if (driver)
|
if (driver)
|
||||||
{
|
{
|
||||||
delete driver;
|
delete driver;
|
||||||
// debugSerial<<F("Driver destroyed")<<endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,9 +55,10 @@ e-mail anklimov@gmail.com
|
|||||||
#define CH_PID 13
|
#define CH_PID 13
|
||||||
#define CH_MBUS 14
|
#define CH_MBUS 14
|
||||||
#define CH_UARTBRIDGE 15
|
#define CH_UARTBRIDGE 15
|
||||||
#define CH_ELEVATOR 16
|
#define CH_RELAYX 16
|
||||||
#define CH_RGBWW 17
|
#define CH_RGBWW 17
|
||||||
#define CH_MULTIVENT 18
|
#define CH_MULTIVENT 18
|
||||||
|
#define CH_ELEVATOR 19
|
||||||
|
|
||||||
//#define CHANNEL_TYPES 13
|
//#define CHANNEL_TYPES 13
|
||||||
|
|
||||||
|
|||||||
@@ -970,7 +970,7 @@ bool itemCmd::loadItem(Item * item, uint16_t optionsFlag)
|
|||||||
cmd.itemArgType= subtype;
|
cmd.itemArgType= subtype;
|
||||||
if (optionsFlag & SEND_PARAMETERS) param.asInt32 = item->getVal();
|
if (optionsFlag & SEND_PARAMETERS) param.asInt32 = item->getVal();
|
||||||
//debugSerial<<F("Loaded :");
|
//debugSerial<<F("Loaded :");
|
||||||
debugOut();
|
//debugOut();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1108,7 +1108,7 @@ void Changed(int i, DeviceAddress addr, float currentTemp) {
|
|||||||
debugSerial<<endl<<F("T:")<<currentTemp<<F("<")<<addrstr<<F(">")<<endl;
|
debugSerial<<endl<<F("T:")<<currentTemp<<F("<")<<addrstr<<F(">")<<endl;
|
||||||
aJsonObject *owObj = aJson.getObjectItem(owArr, addrstr);
|
aJsonObject *owObj = aJson.getObjectItem(owArr, addrstr);
|
||||||
if ((currentTemp != -127.0) && (currentTemp != 85.0) && (currentTemp != 0.0))
|
if ((currentTemp != -127.0) && (currentTemp != 85.0) && (currentTemp != 0.0))
|
||||||
executeCommand(owObj,-1,itemCmd(currentTemp));
|
executeCommand(owObj,-1,itemCmd(currentTemp).setSuffix(S_VAL));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (owObj) {
|
if (owObj) {
|
||||||
@@ -1322,7 +1322,11 @@ setupSyslog();
|
|||||||
|
|
||||||
printConfigSummary();
|
printConfigSummary();
|
||||||
configLoaded=true;
|
configLoaded=true;
|
||||||
ethClient.stop(); //Refresh MQTT connection
|
if (ethClient.connected())
|
||||||
|
{
|
||||||
|
ethClient.stop(); //Refresh MQTT connection
|
||||||
|
lanStatus=IP_READY_CONFIG_LOADED_CONNECTING_TO_BROKER;
|
||||||
|
}
|
||||||
configLocked--;
|
configLocked--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,27 +28,37 @@ bool out_pid::getConfig()
|
|||||||
errorSerial<<F("Invalid PID param array.")<<endl;
|
errorSerial<<F("Invalid PID param array.")<<endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
double outMin=0.;
|
double outMin=0.; //UNUSED
|
||||||
double outMax=255.;
|
double outMax=255.;//UNUSED
|
||||||
|
unsigned int alarmTO=0;
|
||||||
|
|
||||||
aJsonObject * param;
|
aJsonObject * param;
|
||||||
switch (aJson.getArraySize(kPIDObj))
|
switch (aJson.getArraySize(kPIDObj))
|
||||||
{ case 5:
|
{ case 7: //kP,kI,kD, alarmTO, alarmVal, outMin, outMax
|
||||||
param = aJson.getArrayItem(kPIDObj, 4);
|
param = aJson.getArrayItem(kPIDObj, 6);
|
||||||
if (param->type == aJson_Float) outMax=param->valuefloat;
|
if (param->type == aJson_Float) outMax=param->valuefloat;
|
||||||
else if (param->type == aJson_Int) outMax=param->valueint;
|
else if (param->type == aJson_Int) outMax=param->valueint;
|
||||||
case 4:
|
|
||||||
param = aJson.getArrayItem(kPIDObj, 3);
|
case 6: //kP,kI,kD, alarmTO, alarmVal, outMin
|
||||||
|
param = aJson.getArrayItem(kPIDObj, 5);
|
||||||
if (param->type == aJson_Float) outMin=param->valuefloat;
|
if (param->type == aJson_Float) outMin=param->valuefloat;
|
||||||
else if (param->type == aJson_Int) outMin=param->valueint;
|
else if (param->type == aJson_Int) outMin=param->valueint;
|
||||||
case 3:
|
|
||||||
|
case 5: //kP,kI,kD, alarmTO, alarmVal
|
||||||
|
case 4: //kP,kI,kD, alarmTO
|
||||||
|
param = aJson.getArrayItem(kPIDObj, 3);
|
||||||
|
if (param->type == aJson_Int) alarmTO=param->valueint;
|
||||||
|
case 3: //kP,kI,kD
|
||||||
param = aJson.getArrayItem(kPIDObj, 2);
|
param = aJson.getArrayItem(kPIDObj, 2);
|
||||||
if (param->type == aJson_Float) kD=param->valuefloat;
|
if (param->type == aJson_Float) kD=param->valuefloat;
|
||||||
else if (param->type == aJson_Int) kD=param->valueint;
|
else if (param->type == aJson_Int) kD=param->valueint;
|
||||||
case 2:
|
|
||||||
|
case 2: //kP,kI
|
||||||
param = aJson.getArrayItem(kPIDObj, 1);
|
param = aJson.getArrayItem(kPIDObj, 1);
|
||||||
if (param->type == aJson_Float) kI=param->valuefloat;
|
if (param->type == aJson_Float) kI=param->valuefloat;
|
||||||
else if (param->type == aJson_Int) kI=param->valueint;
|
else if (param->type == aJson_Int) kI=param->valueint;
|
||||||
case 1:
|
|
||||||
|
case 1: //kP
|
||||||
param = aJson.getArrayItem(kPIDObj, 0);
|
param = aJson.getArrayItem(kPIDObj, 0);
|
||||||
if (param->type == aJson_Float) kP=param->valuefloat;
|
if (param->type == aJson_Float) kP=param->valuefloat;
|
||||||
else if (param->type == aJson_Int) kP=param->valueint;
|
else if (param->type == aJson_Int) kP=param->valueint;
|
||||||
@@ -56,7 +66,7 @@ bool out_pid::getConfig()
|
|||||||
{
|
{
|
||||||
kP=-kP;
|
kP=-kP;
|
||||||
direction=REVERSE;
|
direction=REVERSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (item->itemVal->type)
|
switch (item->itemVal->type)
|
||||||
@@ -79,6 +89,9 @@ bool out_pid::getConfig()
|
|||||||
store->pid->SetMode(AUTOMATIC);
|
store->pid->SetMode(AUTOMATIC);
|
||||||
//store->pid->SetOutputLimits(outMin,outMax);
|
//store->pid->SetOutputLimits(outMin,outMax);
|
||||||
store->pid->SetSampleTime(5000);
|
store->pid->SetSampleTime(5000);
|
||||||
|
store->alarmTimer=millis();
|
||||||
|
store->alarmArmed=false;
|
||||||
|
store->alarmTimeout=alarmTO; //in sec
|
||||||
|
|
||||||
return true;}
|
return true;}
|
||||||
else errorSerial<<F("PID already initialized")<<endl;
|
else errorSerial<<F("PID already initialized")<<endl;
|
||||||
@@ -99,7 +112,10 @@ store->pid=NULL;
|
|||||||
if (getConfig())
|
if (getConfig())
|
||||||
{
|
{
|
||||||
infoSerial<<F("PID config loaded ")<< item->itemArr->name<<endl;
|
infoSerial<<F("PID config loaded ")<< item->itemArr->name<<endl;
|
||||||
item->On(); // Turn ON pid by default
|
//item->On(); // Turn ON pid by default
|
||||||
|
// if (item->getCmd()) item->setFlag(SEND_COMMAND);
|
||||||
|
// if (item->itemVal) item->setFlag(SEND_PARAMETERS);
|
||||||
|
store->prevOut = -2.0;
|
||||||
store->driverStatus = CST_INITIALIZED;
|
store->driverStatus = CST_INITIALIZED;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -138,21 +154,92 @@ int out_pid::Poll(short cause)
|
|||||||
{
|
{
|
||||||
if (store && store->pid && (Status() == CST_INITIALIZED) && item && (item->getCmd()!=CMD_OFF))
|
if (store && store->pid && (Status() == CST_INITIALIZED) && item && (item->getCmd()!=CMD_OFF))
|
||||||
{
|
{
|
||||||
double prevOut=store->output;
|
//double prevOut=store->output;
|
||||||
if(store->pid->Compute())
|
//itemCmd st;
|
||||||
//if (abs(store->output-store-prevOut)>OUTPUT_TRESHOLD)
|
//st.loadItem(item);
|
||||||
|
//short cmd = st.getCmd();
|
||||||
|
if (item->getCmd() != CMD_OFF)
|
||||||
|
{
|
||||||
|
if(store->pid->Compute() && !store->alarmArmed)
|
||||||
|
if (abs(store->output-store->prevOut)>OUTPUT_TRESHOLD)
|
||||||
{
|
{
|
||||||
aJsonObject * oCmd = aJson.getArrayItem(item->itemArg, 1);
|
aJsonObject * oCmd = aJson.getArrayItem(item->itemArg, 1);
|
||||||
itemCmd value((float) (store->output));// * (100./255.)));
|
itemCmd value((float) (store->output));// * (100./255.)));
|
||||||
|
value.setSuffix(S_SET);
|
||||||
executeCommand(oCmd,-1,value);
|
executeCommand(oCmd,-1,value);
|
||||||
|
store->prevOut=store->output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!store->alarmArmed && isTimeOver(store->alarmTimer,millis(),store->alarmTimeout*1000) )
|
||||||
|
{
|
||||||
|
store->alarmArmed=true;
|
||||||
|
alarm(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;//store->pollingInterval;
|
return 1;//store->pollingInterval;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void out_pid::alarm(bool state)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!item || item->itemArg) return;
|
||||||
|
if (state)
|
||||||
|
{
|
||||||
|
|
||||||
|
aJsonObject * kPIDObj = aJson.getArrayItem(item->itemArg, 0);
|
||||||
|
if (kPIDObj->type != aJson_Array)
|
||||||
|
{
|
||||||
|
errorSerial<<F("Invalid PID param array.")<<endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float outAlarm=0.;
|
||||||
|
double kP=0.;
|
||||||
|
|
||||||
|
bool alarmValDefined = false;
|
||||||
|
aJsonObject * param;
|
||||||
|
switch (aJson.getArraySize(kPIDObj))
|
||||||
|
{
|
||||||
|
case 7: //kP,kI,kD, alarmTO, alarmVal, outMin, outMax
|
||||||
|
case 6: //kP,kI,kD, alarmTO, alarmVal, outMin
|
||||||
|
case 5: //kP,kI,kD, alarmTO, alarmVal
|
||||||
|
param = aJson.getArrayItem(kPIDObj, 4);
|
||||||
|
alarmValDefined=true;
|
||||||
|
if (param->type == aJson_Float) outAlarm=param->valuefloat;
|
||||||
|
else if (param->type == aJson_Int) outAlarm=param->valueint;
|
||||||
|
else alarmValDefined=false;
|
||||||
|
|
||||||
|
case 4: //kP,kI,kD, alarmTO
|
||||||
|
case 3: //kP,kI,kD
|
||||||
|
case 2: //kP,kI
|
||||||
|
case 1: //kP
|
||||||
|
param = aJson.getArrayItem(kPIDObj, 0);
|
||||||
|
if (param->type == aJson_Float) kP=param->valuefloat;
|
||||||
|
else if (param->type == aJson_Int) kP=param->valueint;
|
||||||
|
{
|
||||||
|
if (kP<0)
|
||||||
|
{
|
||||||
|
if (!alarmValDefined) outAlarm = 0.;
|
||||||
|
}
|
||||||
|
else if (!alarmValDefined) outAlarm = .255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errorSerial<<item->itemArr->name<<F(" PID alarm. Set out to ")<<outAlarm<<endl;
|
||||||
|
|
||||||
|
aJsonObject * oCmd = aJson.getArrayItem(item->itemArg, 1);
|
||||||
|
itemCmd value (outAlarm);// * (100./255.)));
|
||||||
|
executeCommand(oCmd,-1,value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
infoSerial<<item->itemArr->name<<F(" PID alarm: closed")<<endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int out_pid::getChanType()
|
int out_pid::getChanType()
|
||||||
{
|
{
|
||||||
return CH_THERMO;
|
return CH_THERMO;
|
||||||
@@ -180,6 +267,13 @@ case S_VAL:
|
|||||||
if (!cmd.isValue()) return 0;
|
if (!cmd.isValue()) return 0;
|
||||||
store->input=cmd.getFloat();
|
store->input=cmd.getFloat();
|
||||||
debugSerial<<F("Input value:")<<store->input<<endl;
|
debugSerial<<F("Input value:")<<store->input<<endl;
|
||||||
|
|
||||||
|
store->alarmTimer=millis();
|
||||||
|
if (store->alarmArmed)
|
||||||
|
{
|
||||||
|
alarm(false);
|
||||||
|
store->alarmArmed=false;
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
//break;
|
//break;
|
||||||
|
|
||||||
@@ -196,17 +290,40 @@ return 1;
|
|||||||
//break;
|
//break;
|
||||||
|
|
||||||
case S_CMD:
|
case S_CMD:
|
||||||
switch (cmd.getCmd())
|
{
|
||||||
|
aJsonObject * oCmd = aJson.getArrayItem(item->itemArg, 1);
|
||||||
|
short command = cmd.getCmd();
|
||||||
|
itemCmd value(ST_VOID,command);
|
||||||
|
value.setSuffix(S_CMD);
|
||||||
|
switch (command)
|
||||||
{
|
{
|
||||||
case CMD_ON:
|
|
||||||
case CMD_OFF:
|
case CMD_OFF:
|
||||||
//item->setCmd(cmd.getCmd());
|
//value.Percents255(0);
|
||||||
//item->SendStatus(SEND_COMMAND);
|
|
||||||
|
case CMD_ON:
|
||||||
|
case CMD_HEAT:
|
||||||
|
case CMD_COOL:
|
||||||
|
case CMD_AUTO:
|
||||||
|
case CMD_FAN:
|
||||||
|
case CMD_DRY:
|
||||||
|
|
||||||
|
executeCommand(oCmd,-1,value);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
case CMD_OFF:
|
||||||
|
{
|
||||||
|
aJsonObject * oCmd = aJson.getArrayItem(item->itemArg, 1);
|
||||||
|
itemCmd value((float) 0.);// * (100./255.)));
|
||||||
|
value.setSuffix(S_SET);
|
||||||
|
executeCommand(oCmd,-1,value);
|
||||||
return 1;
|
return 1;
|
||||||
|
} */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
debugSerial<<F("Unknown cmd ")<<cmd.getCmd()<<endl;
|
debugSerial<<F("Unknown cmd ")<<cmd.getCmd()<<endl;
|
||||||
} //switch cmd
|
} //switch cmd
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
debugSerial<<F("Unknown suffix ")<<suffixCode<<endl;
|
debugSerial<<F("Unknown suffix ")<<suffixCode<<endl;
|
||||||
} //switch suffix
|
} //switch suffix
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include <PID_v1.h>
|
#include <PID_v1.h>
|
||||||
#include "itemCmd.h"
|
#include "itemCmd.h"
|
||||||
|
|
||||||
#define OUTPUT_TRESHOLD 1
|
#define OUTPUT_TRESHOLD 1.0
|
||||||
|
|
||||||
class pidPersistent : public chPersistent {
|
class pidPersistent : public chPersistent {
|
||||||
public:
|
public:
|
||||||
@@ -16,6 +16,9 @@ public:
|
|||||||
double setpoint;
|
double setpoint;
|
||||||
float prevOut;
|
float prevOut;
|
||||||
int driverStatus;
|
int driverStatus;
|
||||||
|
uint32_t alarmTimer;
|
||||||
|
bool alarmArmed;
|
||||||
|
uint16_t alarmTimeout; //in sec
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -32,6 +35,7 @@ public:
|
|||||||
int getChanType() override;
|
int getChanType() override;
|
||||||
int getDefaultStorageType(){return ST_FLOAT;};
|
int getDefaultStorageType(){return ST_FLOAT;};
|
||||||
int Ctrl(itemCmd cmd, char* subItem=NULL, bool toExecute=true) override;
|
int Ctrl(itemCmd cmd, char* subItem=NULL, bool toExecute=true) override;
|
||||||
|
void alarm(bool);
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
204
lighthub/modules/out_relay.cpp
Normal file
204
lighthub/modules/out_relay.cpp
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
#ifndef RELAY_DISABLE
|
||||||
|
#include "modules/out_relay.h"
|
||||||
|
#include "Arduino.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "Streaming.h"
|
||||||
|
|
||||||
|
#include "item.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "dmx.h"
|
||||||
|
|
||||||
|
static int driverStatus = CST_UNKNOWN;
|
||||||
|
|
||||||
|
void out_relay::getConfig()
|
||||||
|
{
|
||||||
|
inverted=false;
|
||||||
|
pin=item->getArg(0);
|
||||||
|
if (pin<0)
|
||||||
|
{
|
||||||
|
pin=-pin;
|
||||||
|
inverted=true;
|
||||||
|
}
|
||||||
|
if(pin==0 || pin>=PINS_COUNT) pin=32;
|
||||||
|
period = item->getArg(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ACTIVE (inverted)?LOW:HIGH
|
||||||
|
#define INACTIVE (inverted)?HIGH:LOW
|
||||||
|
|
||||||
|
|
||||||
|
int out_relay::Setup()
|
||||||
|
{
|
||||||
|
abstractOut::Setup();
|
||||||
|
|
||||||
|
debugSerial<<F("Relay-Out #")<<pin<<F(" init")<<endl;
|
||||||
|
if (!item ) return 0;
|
||||||
|
pinMode(pin, OUTPUT);
|
||||||
|
item->setExt(0);
|
||||||
|
digitalWrite(pin,INACTIVE);
|
||||||
|
//if (item->getCmd()) item->setFlag(SEND_COMMAND);
|
||||||
|
//if (item->itemVal) item->setFlag(SEND_PARAMETERS);
|
||||||
|
driverStatus = CST_INITIALIZED;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int out_relay::Stop()
|
||||||
|
{
|
||||||
|
debugSerial<<F("Relay-Out #")<<pin<<F(" stop")<<endl;
|
||||||
|
pinMode(pin, INPUT);
|
||||||
|
driverStatus = CST_UNKNOWN;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int out_relay::Status()
|
||||||
|
{
|
||||||
|
return driverStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char action_P[] PROGMEM = "/action";
|
||||||
|
const char cooling_P[] PROGMEM = "cooling";
|
||||||
|
const char heating_P[] PROGMEM = "heating";
|
||||||
|
const char drying_P[] PROGMEM = "drying";
|
||||||
|
const char idle_P[] PROGMEM = "idle";
|
||||||
|
const char fan_P[] PROGMEM = "fan";
|
||||||
|
const char off_P[] PROGMEM = "off";
|
||||||
|
|
||||||
|
|
||||||
|
void out_relay::relay(bool state)
|
||||||
|
{
|
||||||
|
char subtopic[10];
|
||||||
|
char val[10];
|
||||||
|
digitalWrite(pin,(state)?ACTIVE:INACTIVE);
|
||||||
|
if (period<1000) return;
|
||||||
|
debugSerial<<F("Out ")<<pin<<F(" is ")<<(state)<<endl;
|
||||||
|
|
||||||
|
strcpy_P(subtopic,action_P);
|
||||||
|
short cmd=item->getCmd();
|
||||||
|
if (state)
|
||||||
|
switch(cmd)
|
||||||
|
{
|
||||||
|
case CMD_COOL:
|
||||||
|
strcpy_P(val,cooling_P);
|
||||||
|
break;
|
||||||
|
//case CMD_AUTO:
|
||||||
|
//case CMD_HEAT:
|
||||||
|
//case CMD_ON:
|
||||||
|
//
|
||||||
|
// break;
|
||||||
|
case CMD_DRY:
|
||||||
|
strcpy_P(val,drying_P);
|
||||||
|
break;
|
||||||
|
case CMD_FAN:
|
||||||
|
strcpy_P(val,fan_P);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
strcpy_P(val,heating_P);
|
||||||
|
}
|
||||||
|
else //turned off
|
||||||
|
if (cmd==CMD_OFF) strcpy_P(val,off_P);
|
||||||
|
else strcpy_P(val,idle_P);
|
||||||
|
|
||||||
|
publishTopic(item->itemArr->name,val,subtopic);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getPinVal(uint8_t pin)
|
||||||
|
{return (0!=(*portOutputRegister( digitalPinToPort(pin) ) & digitalPinToBitMask(pin)));}
|
||||||
|
|
||||||
|
int out_relay::Poll(short cause)
|
||||||
|
{
|
||||||
|
if (!item) return 0;
|
||||||
|
|
||||||
|
itemCmd st;
|
||||||
|
st.loadItem(item);
|
||||||
|
int val = st.getPercents255();
|
||||||
|
short cmd = st.getCmd();
|
||||||
|
uint32_t timer = item->getExt();
|
||||||
|
|
||||||
|
if (timer && isTimeOver(timer,millis(),period))
|
||||||
|
{
|
||||||
|
item->setExt(millisNZ());
|
||||||
|
if (val && (getPinVal(pin) == INACTIVE)) relay(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (timer && (getPinVal(pin) == ACTIVE) && isTimeOver(timer,millis(),period*val/255))
|
||||||
|
{
|
||||||
|
relay(false);
|
||||||
|
if (!item->isActive()) item->setExt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int out_relay::Ctrl(itemCmd cmd, char* subItem, bool toExecute)
|
||||||
|
{
|
||||||
|
debugSerial<<F("relayCtr: ");
|
||||||
|
cmd.debugOut();
|
||||||
|
int suffixCode;
|
||||||
|
if (cmd.isCommand()) suffixCode = S_CMD;
|
||||||
|
else suffixCode = cmd.getSuffix();
|
||||||
|
|
||||||
|
switch(suffixCode)
|
||||||
|
{
|
||||||
|
case S_NOTFOUND:
|
||||||
|
// turn on and set
|
||||||
|
toExecute = true;
|
||||||
|
case S_SET:
|
||||||
|
if (toExecute)
|
||||||
|
{
|
||||||
|
if (cmd.getPercents255())
|
||||||
|
{
|
||||||
|
if (!item->getExt())
|
||||||
|
{
|
||||||
|
item->setExt(millisNZ());
|
||||||
|
relay(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item->setExt(0);
|
||||||
|
relay(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
case S_CMD:
|
||||||
|
|
||||||
|
switch (cmd.getCmd())
|
||||||
|
{
|
||||||
|
case CMD_ON:
|
||||||
|
case CMD_HEAT:
|
||||||
|
case CMD_COOL:
|
||||||
|
case CMD_AUTO:
|
||||||
|
case CMD_FAN:
|
||||||
|
case CMD_DRY:
|
||||||
|
if (!item->getExt())
|
||||||
|
{
|
||||||
|
item->setExt(millisNZ());
|
||||||
|
relay(true);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case CMD_OFF:
|
||||||
|
item->setExt(0);
|
||||||
|
relay(false);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
default:
|
||||||
|
debugSerial<<F("Unknown cmd ")<<cmd.getCmd()<<endl;
|
||||||
|
} //switch cmd
|
||||||
|
|
||||||
|
default:
|
||||||
|
debugSerial<<F("Unknown suffix ")<<suffixCode<<endl;
|
||||||
|
} //switch suffix
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int out_relay::getChanType()
|
||||||
|
{
|
||||||
|
return CH_PWM;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
28
lighthub/modules/out_relay.h
Normal file
28
lighthub/modules/out_relay.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "options.h"
|
||||||
|
#ifndef RELAY_DISABLE
|
||||||
|
|
||||||
|
#include <abstractout.h>
|
||||||
|
#include <item.h>
|
||||||
|
|
||||||
|
class out_relay : public abstractOut {
|
||||||
|
public:
|
||||||
|
|
||||||
|
out_relay(Item * _item):abstractOut(_item){ getConfig();};
|
||||||
|
void getConfig();
|
||||||
|
void relay(bool state);
|
||||||
|
int Setup() override;
|
||||||
|
int Poll(short cause) override;
|
||||||
|
int Stop() override;
|
||||||
|
int Status() override;
|
||||||
|
|
||||||
|
int getChanType() override;
|
||||||
|
int Ctrl(itemCmd cmd, char* subItem=NULL, bool toExecute=true) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
short pin;
|
||||||
|
bool inverted;
|
||||||
|
uint32_t period;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user