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()
|
||||
{
|
||||
if (item) item->setCmd(CMD_OFF);
|
||||
if (item && (item->getCmd()==-1)) item->setCmd(CMD_OFF);
|
||||
return 1;
|
||||
}
|
||||
@@ -50,6 +50,7 @@ e-mail anklimov@gmail.com
|
||||
#include "modules/out_pid.h"
|
||||
#include "modules/out_multivent.h"
|
||||
#include "modules/out_uartbridge.h"
|
||||
#include "modules/out_relay.h"
|
||||
|
||||
#ifdef ELEVATOR_ENABLE
|
||||
#include "modules/out_elevator.h"
|
||||
@@ -147,48 +148,48 @@ void Item::Parse() {
|
||||
case CH_DIMMER:
|
||||
case CH_RGBWW:
|
||||
driver = new out_dmx (this);
|
||||
// debugSerial<<F("DMX driver created")<<endl;
|
||||
break;
|
||||
#endif
|
||||
#ifndef SPILED_DISABLE
|
||||
case CH_SPILED:
|
||||
driver = new out_SPILed (this);
|
||||
// debugSerial<<F("SPILED driver created")<<endl;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifndef AC_DISABLE
|
||||
case CH_AC:
|
||||
driver = new out_AC (this);
|
||||
// debugSerial<<F("AC driver created")<<endl;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifndef MOTOR_DISABLE
|
||||
case CH_MOTOR:
|
||||
driver = new out_Motor (this);
|
||||
// debugSerial<<F("AC driver created")<<endl;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifndef MBUS_DISABLE
|
||||
case CH_MBUS:
|
||||
driver = new out_Modbus (this);
|
||||
// debugSerial<<F("AC driver created")<<endl;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifndef PID_DISABLE
|
||||
case CH_PID:
|
||||
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;
|
||||
#endif
|
||||
|
||||
#ifndef MULTIVENT_DISABLE
|
||||
case CH_MULTIVENT:
|
||||
driver = new out_Multivent (this);
|
||||
// debugSerial<<F("AC driver created")<<endl;
|
||||
break;
|
||||
#endif
|
||||
|
||||
@@ -217,7 +218,11 @@ boolean Item::Setup()
|
||||
if (driver)
|
||||
{
|
||||
if (driver->Status()) driver->Stop();
|
||||
driver->Setup();
|
||||
if (driver->Setup())
|
||||
{
|
||||
if (getCmd()) setFlag(SEND_COMMAND);
|
||||
if (itemVal) setFlag(SEND_PARAMETERS);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
@@ -237,7 +242,6 @@ Item::~Item()
|
||||
if (driver)
|
||||
{
|
||||
delete driver;
|
||||
// debugSerial<<F("Driver destroyed")<<endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,9 +55,10 @@ e-mail anklimov@gmail.com
|
||||
#define CH_PID 13
|
||||
#define CH_MBUS 14
|
||||
#define CH_UARTBRIDGE 15
|
||||
#define CH_ELEVATOR 16
|
||||
#define CH_RELAYX 16
|
||||
#define CH_RGBWW 17
|
||||
#define CH_MULTIVENT 18
|
||||
#define CH_ELEVATOR 19
|
||||
|
||||
//#define CHANNEL_TYPES 13
|
||||
|
||||
|
||||
@@ -970,7 +970,7 @@ bool itemCmd::loadItem(Item * item, uint16_t optionsFlag)
|
||||
cmd.itemArgType= subtype;
|
||||
if (optionsFlag & SEND_PARAMETERS) param.asInt32 = item->getVal();
|
||||
//debugSerial<<F("Loaded :");
|
||||
debugOut();
|
||||
//debugOut();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1108,7 +1108,7 @@ void Changed(int i, DeviceAddress addr, float currentTemp) {
|
||||
debugSerial<<endl<<F("T:")<<currentTemp<<F("<")<<addrstr<<F(">")<<endl;
|
||||
aJsonObject *owObj = aJson.getObjectItem(owArr, addrstr);
|
||||
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) {
|
||||
@@ -1322,7 +1322,11 @@ setupSyslog();
|
||||
|
||||
printConfigSummary();
|
||||
configLoaded=true;
|
||||
ethClient.stop(); //Refresh MQTT connection
|
||||
if (ethClient.connected())
|
||||
{
|
||||
ethClient.stop(); //Refresh MQTT connection
|
||||
lanStatus=IP_READY_CONFIG_LOADED_CONNECTING_TO_BROKER;
|
||||
}
|
||||
configLocked--;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,27 +28,37 @@ bool out_pid::getConfig()
|
||||
errorSerial<<F("Invalid PID param array.")<<endl;
|
||||
return false;
|
||||
}
|
||||
double outMin=0.;
|
||||
double outMax=255.;
|
||||
double outMin=0.; //UNUSED
|
||||
double outMax=255.;//UNUSED
|
||||
unsigned int alarmTO=0;
|
||||
|
||||
aJsonObject * param;
|
||||
switch (aJson.getArraySize(kPIDObj))
|
||||
{ case 5:
|
||||
param = aJson.getArrayItem(kPIDObj, 4);
|
||||
{ case 7: //kP,kI,kD, alarmTO, alarmVal, outMin, outMax
|
||||
param = aJson.getArrayItem(kPIDObj, 6);
|
||||
if (param->type == aJson_Float) outMax=param->valuefloat;
|
||||
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;
|
||||
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);
|
||||
if (param->type == aJson_Float) kD=param->valuefloat;
|
||||
else if (param->type == aJson_Int) kD=param->valueint;
|
||||
case 2:
|
||||
|
||||
case 2: //kP,kI
|
||||
param = aJson.getArrayItem(kPIDObj, 1);
|
||||
if (param->type == aJson_Float) kI=param->valuefloat;
|
||||
else if (param->type == aJson_Int) kI=param->valueint;
|
||||
case 1:
|
||||
|
||||
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;
|
||||
@@ -79,6 +89,9 @@ bool out_pid::getConfig()
|
||||
store->pid->SetMode(AUTOMATIC);
|
||||
//store->pid->SetOutputLimits(outMin,outMax);
|
||||
store->pid->SetSampleTime(5000);
|
||||
store->alarmTimer=millis();
|
||||
store->alarmArmed=false;
|
||||
store->alarmTimeout=alarmTO; //in sec
|
||||
|
||||
return true;}
|
||||
else errorSerial<<F("PID already initialized")<<endl;
|
||||
@@ -99,7 +112,10 @@ store->pid=NULL;
|
||||
if (getConfig())
|
||||
{
|
||||
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;
|
||||
return 1;
|
||||
}
|
||||
@@ -138,21 +154,92 @@ int out_pid::Poll(short cause)
|
||||
{
|
||||
if (store && store->pid && (Status() == CST_INITIALIZED) && item && (item->getCmd()!=CMD_OFF))
|
||||
{
|
||||
double prevOut=store->output;
|
||||
if(store->pid->Compute())
|
||||
//if (abs(store->output-store-prevOut)>OUTPUT_TRESHOLD)
|
||||
//double prevOut=store->output;
|
||||
//itemCmd st;
|
||||
//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);
|
||||
itemCmd value((float) (store->output));// * (100./255.)));
|
||||
value.setSuffix(S_SET);
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
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()
|
||||
{
|
||||
return CH_THERMO;
|
||||
@@ -180,6 +267,13 @@ case S_VAL:
|
||||
if (!cmd.isValue()) return 0;
|
||||
store->input=cmd.getFloat();
|
||||
debugSerial<<F("Input value:")<<store->input<<endl;
|
||||
|
||||
store->alarmTimer=millis();
|
||||
if (store->alarmArmed)
|
||||
{
|
||||
alarm(false);
|
||||
store->alarmArmed=false;
|
||||
}
|
||||
return 1;
|
||||
//break;
|
||||
|
||||
@@ -196,17 +290,40 @@ return 1;
|
||||
//break;
|
||||
|
||||
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:
|
||||
//item->setCmd(cmd.getCmd());
|
||||
//item->SendStatus(SEND_COMMAND);
|
||||
//value.Percents255(0);
|
||||
|
||||
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;
|
||||
} */
|
||||
|
||||
default:
|
||||
debugSerial<<F("Unknown cmd ")<<cmd.getCmd()<<endl;
|
||||
} //switch cmd
|
||||
|
||||
}
|
||||
default:
|
||||
debugSerial<<F("Unknown suffix ")<<suffixCode<<endl;
|
||||
} //switch suffix
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <PID_v1.h>
|
||||
#include "itemCmd.h"
|
||||
|
||||
#define OUTPUT_TRESHOLD 1
|
||||
#define OUTPUT_TRESHOLD 1.0
|
||||
|
||||
class pidPersistent : public chPersistent {
|
||||
public:
|
||||
@@ -16,6 +16,9 @@ public:
|
||||
double setpoint;
|
||||
float prevOut;
|
||||
int driverStatus;
|
||||
uint32_t alarmTimer;
|
||||
bool alarmArmed;
|
||||
uint16_t alarmTimeout; //in sec
|
||||
};
|
||||
|
||||
|
||||
@@ -32,6 +35,7 @@ public:
|
||||
int getChanType() override;
|
||||
int getDefaultStorageType(){return ST_FLOAT;};
|
||||
int Ctrl(itemCmd cmd, char* subItem=NULL, bool toExecute=true) override;
|
||||
void alarm(bool);
|
||||
|
||||
|
||||
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