mirror of
https://github.com/anklimov/lighthub
synced 2025-12-06 03:39:49 +03:00
Сounter mod, core & modbus tuned for 1/100th prec
This commit is contained in:
@@ -51,6 +51,7 @@ e-mail anklimov@gmail.com
|
||||
#include "modules/out_multivent.h"
|
||||
#include "modules/out_uartbridge.h"
|
||||
#include "modules/out_relay.h"
|
||||
#include "modules/out_counter.h"
|
||||
|
||||
#ifdef ELEVATOR_ENABLE
|
||||
#include "modules/out_elevator.h"
|
||||
@@ -205,6 +206,12 @@ void Item::Parse() {
|
||||
driver = new out_elevator (this);
|
||||
// debugSerial<<F("AC driver created")<<endl;
|
||||
break;
|
||||
#endif
|
||||
#ifndef COUNTER_DISABLE
|
||||
case CH_COUNTER:
|
||||
driver = new out_counter (this);
|
||||
// debugSerial<<F("AC driver created")<<endl;
|
||||
break;
|
||||
#endif
|
||||
default: ;
|
||||
}
|
||||
@@ -417,7 +424,7 @@ void Item::setVal(long int par) // Only store if VAL is int (autogenerated or c
|
||||
//debugSerial<<F(" Store ")<<F(" Val=")<<par<<endl;
|
||||
itemVal->valueint = par;
|
||||
itemVal->type = aJson_Int;
|
||||
if (itemVal->subtype==ST_TENS) itemVal->subtype=ST_INT32;
|
||||
if (itemVal->subtype==ST_TENS) itemVal->subtype=ST_INT32; //???
|
||||
}
|
||||
|
||||
void Item::setFloatVal(float par) // Only store if VAL is int (autogenerated or config-defined)
|
||||
@@ -426,7 +433,7 @@ void Item::setFloatVal(float par) // Only store if VAL is int (autogenerated or
|
||||
//debugSerial<<F(" Store ")<<F(" Val=")<<par<<endl;
|
||||
itemVal->valuefloat = par;
|
||||
itemVal->type = aJson_Float;
|
||||
if (itemVal->subtype==ST_TENS) itemVal->subtype=ST_FLOAT;
|
||||
if (itemVal->subtype==ST_TENS) itemVal->subtype=ST_FLOAT; //???
|
||||
}
|
||||
|
||||
void Item::setSubtype(uint8_t par) // Only store if VAL is int (autogenerated or config-defined)
|
||||
@@ -525,6 +532,22 @@ else
|
||||
return suffixCode;
|
||||
}
|
||||
|
||||
long int Item::limitSetValue()
|
||||
{
|
||||
int _itemType = itemType;
|
||||
if (driver) _itemType = driver->getChanType();
|
||||
switch (_itemType)
|
||||
{
|
||||
case CH_COUNTER:
|
||||
return 0;
|
||||
case CH_THERMO:
|
||||
return 80;
|
||||
default:
|
||||
return 255;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// myhome/dev/item/subItem
|
||||
int Item::Ctrl(char * payload, char * subItem)
|
||||
{
|
||||
@@ -638,6 +661,14 @@ st.setSuffix(suffixCode);
|
||||
|
||||
return Ctrl(st,subItem);
|
||||
}
|
||||
case CMD_UP:
|
||||
case CMD_DN:
|
||||
{
|
||||
itemCmd Par0 = getNumber((char **) &payload);
|
||||
Par0.Cmd(cmd);
|
||||
Par0.setSuffix(suffixCode);
|
||||
return Ctrl(Par0, subItem);
|
||||
}
|
||||
default: //some known command
|
||||
{
|
||||
int32_t intParam = getInt((char **) &payload);
|
||||
@@ -852,8 +883,8 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
|
||||
case CMD_UP:
|
||||
{
|
||||
itemCmd fallbackCmd=cmd;
|
||||
short step=0;
|
||||
if (cmd.isValue()) step=cmd.getInt();
|
||||
long step=0;
|
||||
if (cmd.isValue()) step=cmd.getTens_raw();
|
||||
if (!step) step=DEFAULT_INC_STEP;
|
||||
if (cmd.getCmd() == CMD_DN) step=-step;
|
||||
|
||||
@@ -867,7 +898,7 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
|
||||
toExecute=true;
|
||||
case S_SET:
|
||||
|
||||
if (cmd.incrementPercents(step))
|
||||
if (cmd.incrementPercents(step,(suffixCode==S_NOTFOUND)?100:limitSetValue()))
|
||||
{
|
||||
status2Send |= SEND_PARAMETERS | SEND_DEFFERED;
|
||||
} else {cmd=fallbackCmd;invalidArgument=true;}
|
||||
@@ -1121,6 +1152,7 @@ if (status2Send) cmd.saveItem(this,status2Send);
|
||||
if (driver) //New style modular code
|
||||
{
|
||||
res = driver->Ctrl(cmd, subItem, toExecute);
|
||||
if (driver->getChanType() == CH_THERMO) status2Send |= SEND_IMMEDIATE;
|
||||
//if (res==-1) status2Send=0; ///////not working
|
||||
}
|
||||
else
|
||||
|
||||
@@ -59,6 +59,7 @@ e-mail anklimov@gmail.com
|
||||
#define CH_RGBWW 17
|
||||
#define CH_MULTIVENT 18
|
||||
#define CH_ELEVATOR 19
|
||||
#define CH_COUNTER 20
|
||||
|
||||
//#define CHANNEL_TYPES 13
|
||||
|
||||
@@ -146,7 +147,7 @@ class Item
|
||||
inline int Toggle(){return Ctrl(itemCmd(ST_VOID,CMD_TOGGLE));};
|
||||
|
||||
protected:
|
||||
|
||||
long int limitSetValue();
|
||||
int VacomSetFan (itemCmd st);
|
||||
int VacomSetHeat(itemCmd st);
|
||||
int modbusDimmerSet(itemCmd st);
|
||||
|
||||
@@ -113,6 +113,8 @@ uint8_t itemCmd::getStoragetypeByChanType(short chanType)
|
||||
break;
|
||||
case CH_RELAY:
|
||||
return ST_VOID;
|
||||
//case CH_COUNTER:
|
||||
//return ST_TENS;
|
||||
default:
|
||||
return ST_VOID;
|
||||
}
|
||||
@@ -236,13 +238,14 @@ uint16_t itemCmd::getS()
|
||||
return param.s;
|
||||
}
|
||||
|
||||
bool itemCmd::incrementPercents(int16_t dif)
|
||||
{ int par=param.v;
|
||||
|
||||
bool itemCmd::incrementPercents(long int dif, long int limit )
|
||||
{ long par=param.v;
|
||||
switch (cmd.itemArgType)
|
||||
{
|
||||
case ST_PERCENTS255:
|
||||
case ST_HSV255:
|
||||
par+=dif;
|
||||
par+=dif/TENS_BASE;
|
||||
if (par>255) par=255;
|
||||
if (par<0) par=0;
|
||||
param.v=par;
|
||||
@@ -251,9 +254,9 @@ bool itemCmd::incrementPercents(int16_t dif)
|
||||
case ST_INT32:
|
||||
case ST_UINT32:
|
||||
par=param.asInt32;
|
||||
par+=dif;
|
||||
if (par>100) par=100;
|
||||
if (par<0) par=0;
|
||||
par+=dif/TENS_BASE;
|
||||
if (par>limit) par=limit;
|
||||
if (limit && par<0) par=0;
|
||||
param.asInt32=par;
|
||||
break;
|
||||
|
||||
@@ -261,18 +264,18 @@ bool itemCmd::incrementPercents(int16_t dif)
|
||||
case ST_FLOAT_CELSIUS:
|
||||
case ST_FLOAT_FARENHEIT:
|
||||
par=param.asfloat;
|
||||
par+=dif;
|
||||
if (par>100) par=100;
|
||||
if (par<0) par=0;
|
||||
par+=dif/TENS_BASE;
|
||||
if (limit && par>limit) par=limit;
|
||||
if (limit && par<0) par=0;
|
||||
param.asfloat=par;
|
||||
break;
|
||||
|
||||
case ST_TENS:
|
||||
|
||||
par=param.asInt32;
|
||||
par+=dif*10;
|
||||
if (par>1000) par=1000;
|
||||
if (par<0) par=0;
|
||||
par+=dif;
|
||||
// if (par>100*TENS_BASE) par=100*TENS_BASE;
|
||||
// if (par<0) par=0;
|
||||
param.asInt32=par;
|
||||
break;
|
||||
|
||||
@@ -282,13 +285,13 @@ bool itemCmd::incrementPercents(int16_t dif)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool itemCmd::incrementH(int16_t dif)
|
||||
bool itemCmd::incrementH(long int dif)
|
||||
{ int par=param.h;
|
||||
switch (cmd.itemArgType)
|
||||
{
|
||||
//case ST_HSV:
|
||||
case ST_HSV255:
|
||||
par+=dif;
|
||||
par+=dif/TENS_BASE;
|
||||
if (par>365) par=0;
|
||||
if (par<0) par=365;
|
||||
break;
|
||||
@@ -299,12 +302,12 @@ param.h=par;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool itemCmd::incrementS(int16_t dif)
|
||||
bool itemCmd::incrementS(long int dif)
|
||||
{int par=param.s;
|
||||
switch (cmd.itemArgType)
|
||||
{
|
||||
case ST_HSV255:
|
||||
par+=dif;
|
||||
par+=dif/TENS_BASE;
|
||||
if (par>100) par=100;
|
||||
if (par<0) par=0;
|
||||
break;
|
||||
@@ -356,7 +359,7 @@ itemCmd itemCmd::assignFrom(itemCmd from, short chanType)
|
||||
param.v=constrain(from.param.asInt32,0,255);
|
||||
break;
|
||||
case ST_TENS:
|
||||
param.v=constrain(from.param.asInt32/10,0,255);
|
||||
param.v=constrain(from.param.asInt32/TENS_BASE,0,255);
|
||||
break;
|
||||
case ST_HSV255:
|
||||
param.h=from.param.h;
|
||||
@@ -420,7 +423,9 @@ itemCmd itemCmd::assignFrom(itemCmd from, short chanType)
|
||||
break;
|
||||
|
||||
case ST_TENS:
|
||||
param.asfloat=from.param.asInt32/10.;
|
||||
//param.asfloat=(float) from.param.asInt32/(float)TENS_BASE;
|
||||
param.asInt32 = from.param.asInt32;
|
||||
cmd.itemArgType=from.cmd.itemArgType;
|
||||
break;
|
||||
case ST_PERCENTS255:
|
||||
param.asfloat=from.param.v;
|
||||
@@ -507,7 +512,7 @@ itemCmd itemCmd::assignFrom(itemCmd from, short chanType)
|
||||
vol=from.param.asInt32;
|
||||
break;
|
||||
case ST_TENS:
|
||||
vol=from.param.asInt32/10;
|
||||
vol=from.param.asInt32/TENS_BASE;
|
||||
break;
|
||||
case ST_FLOAT:
|
||||
vol=from.param.asfloat;
|
||||
@@ -654,12 +659,36 @@ long int itemCmd::getTens()
|
||||
case ST_FLOAT_FARENHEIT:
|
||||
return param.asfloat*10.0;
|
||||
case ST_TENS:
|
||||
return param.aslong;
|
||||
return param.aslong/(TENS_BASE/10);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
long int itemCmd::getTens_raw()
|
||||
{
|
||||
switch (cmd.itemArgType) {
|
||||
|
||||
case ST_INT32:
|
||||
case ST_UINT32:
|
||||
case ST_RGB:
|
||||
case ST_RGBW:
|
||||
|
||||
return param.aslong*TENS_BASE;
|
||||
case ST_PERCENTS255:
|
||||
case ST_HSV255:
|
||||
return param.v*TENS_BASE;
|
||||
|
||||
case ST_FLOAT:
|
||||
case ST_FLOAT_CELSIUS:
|
||||
case ST_FLOAT_FARENHEIT:
|
||||
return param.asfloat*(float)TENS_BASE;
|
||||
case ST_TENS:
|
||||
return param.aslong;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -682,7 +711,7 @@ long int itemCmd::getInt()
|
||||
case ST_FLOAT_FARENHEIT:
|
||||
return param.asfloat;
|
||||
case ST_TENS:
|
||||
return param.aslong/10;
|
||||
return param.aslong/TENS_BASE;
|
||||
|
||||
|
||||
|
||||
@@ -714,7 +743,7 @@ float itemCmd::getFloat()
|
||||
|
||||
return param.aslong;
|
||||
case ST_TENS:
|
||||
return param.aslong/10;
|
||||
return param.aslong/TENS_BASE;
|
||||
|
||||
case ST_PERCENTS255:
|
||||
case ST_HSV255:
|
||||
@@ -758,8 +787,8 @@ short itemCmd::getPercents(bool inverse)
|
||||
else return constrain (param.asfloat,0,100);
|
||||
|
||||
case ST_TENS:
|
||||
if (inverse) return constrain (100-param.asInt32/10,0,100);
|
||||
else return constrain(param.asInt32/10,0,100);
|
||||
if (inverse) return constrain (100-param.asInt32/TENS_BASE,0,100);
|
||||
else return constrain(param.asInt32/TENS_BASE,0,100);
|
||||
case ST_VOID:
|
||||
return 0;
|
||||
|
||||
@@ -784,7 +813,7 @@ bool itemCmd::setPercents(int percents)
|
||||
param.asfloat=map(percents,0,100,0,255);;
|
||||
break;
|
||||
case ST_TENS:
|
||||
param.asInt32 = map(percents,0,100,0,2550);;
|
||||
param.asInt32 = map(percents,0,100,0,255*TENS_BASE);;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -807,7 +836,7 @@ short itemCmd::getPercents255(bool inverse)
|
||||
if (inverse) return 255-constrain(param.asfloat,0,255); else return constrain(param.asfloat,0,255);
|
||||
|
||||
case ST_TENS:
|
||||
if (inverse) return 255-constrain(param.asInt32/10,0,255); else return constrain(param.asInt32/10,0,255);
|
||||
if (inverse) return 255-constrain(param.asInt32/TENS_BASE,0,255); else return constrain(param.asInt32/TENS_BASE,0,255);
|
||||
|
||||
case ST_VOID:
|
||||
return 0;
|
||||
@@ -908,10 +937,17 @@ itemCmd itemCmd::Float(float f)
|
||||
itemCmd itemCmd::Tens(int32_t i)
|
||||
{
|
||||
cmd.itemArgType=ST_TENS;
|
||||
param.asInt32=i;
|
||||
param.asInt32=i*(TENS_BASE/10);
|
||||
return *this;
|
||||
}
|
||||
|
||||
itemCmd itemCmd::Tens_raw(int32_t i)
|
||||
{
|
||||
cmd.itemArgType=ST_TENS;
|
||||
param.asInt32=i;
|
||||
return *this;
|
||||
}
|
||||
|
||||
itemCmd itemCmd::HSV(uint16_t h, uint8_t s, uint8_t v)
|
||||
{
|
||||
cmd.itemArgType=ST_HSV255;
|
||||
@@ -1002,7 +1038,7 @@ bool itemCmd::loadItem(Item * item, uint16_t optionsFlag)
|
||||
if (subtype)
|
||||
{
|
||||
cmd.itemArgType= subtype;
|
||||
if (optionsFlag & SEND_PARAMETERS) param.asInt32 = item->getVal();
|
||||
if (optionsFlag & SEND_PARAMETERS) param.asInt32 = item->itemVal->valueint;
|
||||
//debugSerial<<F("Loaded :");
|
||||
//debugOut();
|
||||
return true;
|
||||
@@ -1067,8 +1103,9 @@ bool itemCmd::saveItem(Item * item, uint16_t optionsFlag)
|
||||
break;
|
||||
|
||||
default:
|
||||
item->setSubtype(cmd.itemArgType);
|
||||
//item->setSubtype(cmd.itemArgType);
|
||||
item->setVal(param.asInt32);
|
||||
item->setSubtype(cmd.itemArgType);
|
||||
}
|
||||
debugSerial<<F("Saved:");
|
||||
debugOut();
|
||||
@@ -1135,7 +1172,7 @@ char * itemCmd::toString(char * Buffer, int bufLen, int sendFlags, bool scale100
|
||||
snprintf(argPtr, bufLen, "%ld", param.asInt32);
|
||||
break;
|
||||
case ST_TENS:
|
||||
snprintf(argPtr, bufLen, "%ld.%d", param.asInt32/10, abs(param.asInt32 % 10));
|
||||
snprintf(argPtr, bufLen, "%ld.%0"QUOTE(TENS_FRACT_LEN)"d", param.asInt32/TENS_BASE, abs(param.asInt32 % TENS_BASE));
|
||||
break;
|
||||
case ST_HSV255:
|
||||
colorTemp=getColorTemp();
|
||||
@@ -1158,12 +1195,12 @@ char * itemCmd::toString(char * Buffer, int bufLen, int sendFlags, bool scale100
|
||||
float tmpVal = (param.asfloat < 0) ? -param.asfloat : param.asfloat;
|
||||
int tmpInt1 = tmpVal; // Get the integer
|
||||
float tmpFrac = tmpVal - tmpInt1; // Get fraction
|
||||
int tmpInt2 = trunc(tmpFrac * 100); // Turn into integer
|
||||
int tmpInt2 = trunc(tmpFrac * 1000); // Turn into integer
|
||||
// Print as parts, note that you need 0-padding for fractional bit.
|
||||
|
||||
if (param.asfloat < 0)
|
||||
snprintf (argPtr, bufLen, "-%d.%02d", tmpInt1, tmpInt2);
|
||||
else snprintf (argPtr, bufLen, "%d.%02d", tmpInt1, tmpInt2);
|
||||
snprintf (argPtr, bufLen, "-%d.%03d", tmpInt1, tmpInt2);
|
||||
else snprintf (argPtr, bufLen, "%d.%03d", tmpInt1, tmpInt2);
|
||||
}
|
||||
break;
|
||||
case ST_RGB:
|
||||
|
||||
@@ -169,6 +169,7 @@ public:
|
||||
itemCmd Int(uint32_t i);
|
||||
itemCmd Float(float f);
|
||||
itemCmd Tens(int32_t i);
|
||||
itemCmd Tens_raw(int32_t i);
|
||||
itemCmd Cmd(uint8_t i);
|
||||
itemCmd HSV(uint16_t h, uint8_t s, uint8_t v);
|
||||
itemCmd HSV255(uint16_t h, uint8_t s, uint8_t v);
|
||||
@@ -192,12 +193,13 @@ public:
|
||||
uint8_t getSuffix();
|
||||
itemCmd setSuffix(uint8_t suffix);
|
||||
|
||||
bool incrementPercents(int16_t);
|
||||
bool incrementH(int16_t);
|
||||
bool incrementS(int16_t);
|
||||
bool incrementPercents(long int, long int limit);
|
||||
bool incrementH(long int);
|
||||
bool incrementS(long int);
|
||||
|
||||
long int getInt();
|
||||
long int getTens();
|
||||
long int getTens_raw();
|
||||
float getFloat();
|
||||
char * getString();
|
||||
long int getSingleInt();
|
||||
|
||||
132
lighthub/modules/out_counter.cpp
Normal file
132
lighthub/modules/out_counter.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
#ifndef COUNTER_DISABLE
|
||||
#include "modules/out_counter.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_counter::getConfig()
|
||||
{
|
||||
if (!item) return;
|
||||
impulse = item->getFloatArg(0);
|
||||
period = item->getFloatArg(1)*1000.0;
|
||||
}
|
||||
|
||||
int out_counter::Setup()
|
||||
{
|
||||
abstractOut::Setup();
|
||||
driverStatus = CST_INITIALIZED;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int out_counter::Stop()
|
||||
{
|
||||
driverStatus = CST_UNKNOWN;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int out_counter::Status()
|
||||
{
|
||||
return driverStatus;
|
||||
}
|
||||
|
||||
|
||||
int out_counter::Poll(short cause)
|
||||
{
|
||||
if (!item) return 0;
|
||||
|
||||
|
||||
uint32_t timer = item->getExt();
|
||||
|
||||
if (timer && isTimeOver(timer,millis(),period))
|
||||
{
|
||||
item->setExt(millisNZ());
|
||||
itemCmd st;
|
||||
st.loadItem(item);
|
||||
float val = st.getFloat();
|
||||
//short cmd = st.getCmd();
|
||||
val+=period;
|
||||
st.Float(val);
|
||||
st.saveItem(item);
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
int out_counter::Ctrl(itemCmd cmd, char* subItem, bool toExecute)
|
||||
{
|
||||
debugSerial<<F("Counter: ");
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
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_counter::getChanType()
|
||||
{
|
||||
return CH_COUNTER;
|
||||
}
|
||||
#endif
|
||||
26
lighthub/modules/out_counter.h
Normal file
26
lighthub/modules/out_counter.h
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
#pragma once
|
||||
#include "options.h"
|
||||
#ifndef COUNTER_DISABLE
|
||||
|
||||
#include <abstractout.h>
|
||||
#include <item.h>
|
||||
|
||||
class out_counter : public abstractOut {
|
||||
public:
|
||||
|
||||
out_counter(Item * _item):abstractOut(_item){ getConfig();};
|
||||
void getConfig();
|
||||
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:
|
||||
float impulse;
|
||||
uint32_t period;
|
||||
};
|
||||
#endif
|
||||
@@ -39,6 +39,7 @@ struct serial_t
|
||||
#define PAR_U8H 7
|
||||
#define PAR_U8L 8
|
||||
#define PAR_TENS 9
|
||||
#define PAR_100 10
|
||||
|
||||
|
||||
const reg_t regSize_P[] PROGMEM =
|
||||
@@ -51,7 +52,8 @@ const reg_t regSize_P[] PROGMEM =
|
||||
{ "i8l", (uint8_t) PAR_I8L },
|
||||
{ "u8h", (uint8_t) PAR_U8H },
|
||||
{ "u8l", (uint8_t) PAR_U8L },
|
||||
{ "x10", (uint8_t) PAR_TENS }
|
||||
{ "x10", (uint8_t) PAR_TENS },
|
||||
{ "100", (uint8_t) PAR_100 }
|
||||
} ;
|
||||
#define regSizeNum sizeof(regSize_P)/sizeof(reg_t)
|
||||
|
||||
@@ -233,7 +235,7 @@ int out_Modbus::findRegister(int registerNum, int posInBuffer, int regType)
|
||||
bool is8bit = false;
|
||||
while (paramObj)
|
||||
{
|
||||
aJsonObject *regObj;
|
||||
aJsonObject *regObj=NULL;
|
||||
switch (regType) {
|
||||
case MODBUS_HOLDING_REG_TYPE: regObj = aJson.getObjectItem(paramObj, "reg");
|
||||
break;
|
||||
@@ -257,12 +259,13 @@ int out_Modbus::findRegister(int registerNum, int posInBuffer, int regType)
|
||||
|
||||
case PAR_I16:
|
||||
//isSigned=true;
|
||||
param=data;
|
||||
mappedParam.Int((int32_t)data);
|
||||
break;
|
||||
|
||||
case PAR_U16:
|
||||
param=data;
|
||||
mappedParam.Int((uint32_t)data);
|
||||
//param=data;
|
||||
break;
|
||||
case PAR_I32:
|
||||
//isSigned=true;
|
||||
@@ -288,7 +291,14 @@ int out_Modbus::findRegister(int registerNum, int posInBuffer, int regType)
|
||||
break;
|
||||
|
||||
case PAR_TENS:
|
||||
param=data;
|
||||
mappedParam.Tens((int32_t) data);
|
||||
break;
|
||||
|
||||
case PAR_100:
|
||||
param=data;
|
||||
mappedParam.Tens_raw(data * (TENS_BASE/100));
|
||||
mappedParam.Float((int32_t) data/100.);
|
||||
}
|
||||
|
||||
if (mapObj && (mapObj->type==aJson_Array || mapObj->type==aJson_Object))
|
||||
@@ -306,16 +316,24 @@ int out_Modbus::findRegister(int registerNum, int posInBuffer, int regType)
|
||||
aJsonObject *lastMeasured = aJson.getObjectItem(execObj,"@S");
|
||||
if (lastMeasured)
|
||||
{
|
||||
if (lastMeasured->valueint == mappedParam.getSingleInt())
|
||||
if (lastMeasured->valueint == param)
|
||||
submitParam=false; //supress repeating execution for same val
|
||||
else lastMeasured->valueint=mappedParam.getSingleInt();
|
||||
else lastMeasured->valueint=param;
|
||||
}
|
||||
else //No container to store value yet
|
||||
{
|
||||
debugSerial<<F("Add @S: ")<<paramObj->name<<endl;
|
||||
aJson.addNumberToObject(execObj, "@S", mappedParam.getSingleInt());
|
||||
aJson.addNumberToObject(execObj, "@S", (long) param);
|
||||
}
|
||||
if (submitParam) executeCommand(execObj, -1, mappedParam);
|
||||
if (submitParam)
|
||||
{ // Compare with last submitted val
|
||||
aJsonObject *settedValue = aJson.getObjectItem(execObj,"@V");
|
||||
if (settedValue && (settedValue->valueint == param))
|
||||
{
|
||||
debugSerial<<F("Ignored - equal with setted val")<<endl;
|
||||
}
|
||||
else executeCommand(execObj, -1, mappedParam);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!is8bit) return 1;
|
||||
@@ -387,7 +405,7 @@ void out_Modbus::initLine()
|
||||
node.begin(item->getArg(0), modbusSerial);
|
||||
}
|
||||
|
||||
int out_Modbus::sendModbus(char * paramName, uint32_t value, uint8_t regType)
|
||||
int out_Modbus::sendModbus(char * paramName, int32_t value, uint8_t regType)
|
||||
{
|
||||
if (!store) return -1;
|
||||
aJsonObject * templateParamObj = aJson.getObjectItem(store->parameters, paramName);
|
||||
@@ -401,9 +419,12 @@ int out_Modbus::sendModbus(char * paramName, uint32_t value, uint8_t regType)
|
||||
// if (typeObj && typeObj->type == aJson_String) regType=str2regSize(typeObj->valuestring);
|
||||
|
||||
switch(regType) {
|
||||
case PAR_I16:
|
||||
case PAR_U16:
|
||||
//res = node.writeSingleRegister(regObj->valueint,value);
|
||||
//break;
|
||||
case PAR_I16:
|
||||
case PAR_TENS:
|
||||
case PAR_100:
|
||||
res = node.writeSingleRegister(regObj->valueint,value);
|
||||
break;
|
||||
|
||||
@@ -424,7 +445,7 @@ int out_Modbus::sendModbus(char * paramName, uint32_t value, uint8_t regType)
|
||||
res = node.writeSingleRegister(regObj->valueint,(value & 0xFFFF)>> 8);
|
||||
break;
|
||||
}
|
||||
debugSerial<<F("MB_SEND Res: ")<<res<<F(" ")<<paramName<<" reg:"<<regObj->valueint<<F(" val:")<<value<<endl;
|
||||
debugSerial<<F("MB_SEND Res: ")<<res<<F(" ")<<paramName<<" reg:"<<regObj->valueint<<F(" val:")<<value<<F(" ival:")<<(int32_t) value<<endl;
|
||||
return ( res == 0);
|
||||
}
|
||||
|
||||
@@ -458,6 +479,7 @@ if (itemParametersObj && itemParametersObj->type ==aJson_Object)
|
||||
break;
|
||||
case 0: //fault
|
||||
execObj->subtype |= MB_SEND_ERROR;
|
||||
errorSerial<<F("MBus ")<<execObj->name<<F(" send error")<<endl;
|
||||
break;
|
||||
default: //param not found
|
||||
errorSerial<<F("MBus param ")<<execObj->name<<F(" not found")<<endl;
|
||||
@@ -578,6 +600,9 @@ aJsonObject * typeObj = aJson.getObjectItem(templateParamObj, "type");
|
||||
break;
|
||||
case PAR_TENS:
|
||||
Value=cmd.getTens();
|
||||
break;
|
||||
case PAR_100:
|
||||
Value=cmd.getTens_raw()*(100/TENS_BASE);
|
||||
}
|
||||
|
||||
debugSerial<<F("MB suffix:")<<suffixStr<< F(" Val: ")<<Value<<endl;
|
||||
@@ -586,22 +611,32 @@ if (itemParametersObj && itemParametersObj->type ==aJson_Object)
|
||||
{
|
||||
aJsonObject *execObj = aJson.getObjectItem(itemParametersObj,suffixStr);
|
||||
if (execObj && execObj->type == aJson_Object)
|
||||
{
|
||||
execObj->subtype |= MB_NEED_SEND;
|
||||
|
||||
aJsonObject *outValue = aJson.getObjectItem(execObj,"@V");
|
||||
if (outValue)
|
||||
{
|
||||
aJsonObject *polledValue = aJson.getObjectItem(execObj,"@S");
|
||||
if (polledValue && (polledValue->valueint == Value))
|
||||
{
|
||||
outValue->valueint=Value;
|
||||
outValue->subtype =regType;
|
||||
debugSerial<<F("Ignored - not changed")<<endl;
|
||||
}
|
||||
else //No container to store value yet
|
||||
{
|
||||
debugSerial<<F("Add @V: ")<<execObj->name<<endl;
|
||||
aJson.addNumberToObject(execObj, "@V", Value);
|
||||
outValue = aJson.getObjectItem(execObj,"@V");
|
||||
if (outValue) outValue->subtype =regType;
|
||||
}
|
||||
|
||||
else
|
||||
{ //Schedule update
|
||||
execObj->subtype |= MB_NEED_SEND;
|
||||
|
||||
aJsonObject *outValue = aJson.getObjectItem(execObj,"@V");
|
||||
if (outValue)
|
||||
{
|
||||
outValue->valueint=Value;
|
||||
outValue->subtype =regType;
|
||||
polledValue->valueint=Value; //to pevent suppressing to change back to previously polled value if this occurs before next polling
|
||||
}
|
||||
else //No container to store value yet
|
||||
{
|
||||
debugSerial<<F("Add @V: ")<<execObj->name<<endl;
|
||||
aJson.addNumberToObject(execObj, "@V", Value);
|
||||
outValue = aJson.getObjectItem(execObj,"@V");
|
||||
if (outValue) outValue->subtype =regType;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,6 @@ protected:
|
||||
int findRegister(int registerNum, int posInBuffer, int regType);
|
||||
void pollModbus(aJsonObject * reg, int regType);
|
||||
void initLine();
|
||||
int sendModbus(char * paramName, uint32_t value, uint8_t regType);
|
||||
int sendModbus(char * paramName, int32_t value, uint8_t regType);
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -276,8 +276,6 @@ int out_pid::getChanType()
|
||||
int out_pid::Ctrl(itemCmd cmd, char* subItem, bool toExecute)
|
||||
{
|
||||
if (!store || !store->pid || (Status() != CST_INITIALIZED)) return 0;
|
||||
|
||||
|
||||
int suffixCode = cmd.getSuffix();
|
||||
|
||||
if (cmd.isCommand() && !suffixCode) suffixCode=S_CMD; //if some known command find, but w/o correct suffix - got it
|
||||
@@ -307,6 +305,12 @@ case S_SET:
|
||||
if (!cmd.isValue()) return 0;
|
||||
store->setpoint=cmd.getFloat();
|
||||
debugSerial<<F("Setpoint:")<<store->setpoint<<endl;
|
||||
|
||||
{
|
||||
aJsonObject * itemCascadeObj = aJson.getArrayItem(item->itemArg, 2);
|
||||
if (itemCascadeObj) executeCommand(itemCascadeObj,-1,cmd);
|
||||
}
|
||||
|
||||
//cmd.saveItem(item);
|
||||
//item->SendStatus(SEND_PARAMETERS);
|
||||
return 1;
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
|
||||
|
||||
#define TENS_FRACT_LEN 2
|
||||
#define TENS_BASE 100
|
||||
|
||||
#define DEFAULT_FILESIZE_LIMIT 65535
|
||||
#ifndef MAX_JSON_CONF_SIZE
|
||||
|
||||
|
||||
@@ -116,31 +116,45 @@ int getInt(char **chan) {
|
||||
// Function return first retrived number and move pointer to position next after ','
|
||||
itemCmd getNumber(char **chan) {
|
||||
itemCmd val(ST_TENS,CMD_VOID);
|
||||
int fract =0;
|
||||
if (chan && *chan && **chan)
|
||||
{
|
||||
//Skip non-numeric values
|
||||
while (**chan && !(**chan == '-' || (**chan >= '0' && **chan<='9'))) *chan += 1;
|
||||
int ch = atoi(*chan);
|
||||
|
||||
|
||||
long fractnumbers = 0;
|
||||
short fractlen = 0;
|
||||
short intlen = 0;
|
||||
|
||||
char * intptr = * chan;
|
||||
if (*intptr == '-') intptr ++;
|
||||
while (isDigit(*(intptr+intlen))) intlen++;
|
||||
|
||||
char * fractptr = strchr(*chan,'.');
|
||||
if (fractptr)
|
||||
{
|
||||
// fract = atoi(fractptr);
|
||||
// *chan = fractptr;
|
||||
fractptr += 1;
|
||||
fract = constrain(*fractptr-'0',0,9);
|
||||
fractptr ++;
|
||||
while (isDigit(*(fractptr+fractlen))) fractlen++;
|
||||
|
||||
for (short i=0;i<TENS_FRACT_LEN;i++)
|
||||
{
|
||||
fractnumbers = fractnumbers * 10;
|
||||
if (isDigit(*(fractptr+i))) fractnumbers += constrain(*(fractptr+i)-'0',0,9);
|
||||
}
|
||||
}
|
||||
|
||||
if (!fractlen) val.Int(atol(*chan));
|
||||
else if (fractlen<=TENS_FRACT_LEN && intlen+TENS_FRACT_LEN<=9)
|
||||
{
|
||||
long intpart = atol(*chan);
|
||||
val.Tens_raw(intpart*TENS_BASE+((intpart>=0)?fractnumbers:-fractnumbers));
|
||||
}
|
||||
else
|
||||
val.Float(atof(*chan));
|
||||
|
||||
//Move pointer to next element (after ,)
|
||||
*chan = strchr(*chan, ',');
|
||||
if (*chan) *chan += 1;
|
||||
//debugSerialPort.print(F("Par:")); debugSerialPort.println(ch);
|
||||
|
||||
if (fract)
|
||||
val.Tens(ch*10+((ch>0)?fract:-fract));
|
||||
else
|
||||
val.Int((int32_t)ch);
|
||||
|
||||
}
|
||||
//val.debugOut();
|
||||
return val;
|
||||
|
||||
Reference in New Issue
Block a user