Initial commit

This commit is contained in:
2017-10-02 14:13:45 +03:00
parent fb7345b339
commit 6b628d6795
13 changed files with 2814 additions and 0 deletions

126
dmx.cpp Normal file
View File

@@ -0,0 +1,126 @@
#include "dmx.h"
//#include <DmxSimple.h>
//#include <Artnet.h>
//#include <DMXSerial.h>
uint8_t * DMXin = NULL;
int D_State=0;
unsigned long D_checkT=0;
Artnet *artnet = NULL;
aJsonObject *dmxArr = NULL;
void DMXImmediateUpdate(short tch,short r, short g, short b, short w) {
//Here only safe re-interable code for quick passthrow between DMX IN and DMX OUT
if (dmxArr && (dmxArr->type==aJson_Array))
{
char* itemname = aJson.getArrayItem(dmxArr,tch)->valuestring;
itemCtrl2(itemname,r,g,b,w);
}
}
void DMXSemiImmediateUpdate(short tch,short trh, int val)
{
//Here any code for passthrow between DMX IN and DMX OUT in idle state
}
void DMXput(void)
{
int t;
for (short tch=0; tch<=3 ; tch++)
{
short base = tch*4;
DMXImmediateUpdate(tch,DMXin[base],DMXin[base+1],DMXin[base+2],DMXin[base+3]);
}
};
void DMXUpdate(void)
{
int t;
for (short tch=0; tch<=3 ; tch++)
{
short base = tch*4;
bool updated = 0;
for (short trh=0; trh<4 ; trh++)
if ((t=DMXSerial.read(base+trh+1)) != DMXin[base+trh])
{
D_State |= (1<<tch);
updated=1;
//Serial.print("Changed :"); Serial.print(DMXin[tch*4+trh]); Serial.print(" => "); Serial.print(t);Serial.println();
DMXin[base+trh]=t;
//DMXImmediateUpdate(tch,trh,t);
//break;
}
if (updated)
{
DMXImmediateUpdate(tch,DMXin[base],DMXin[base+1],DMXin[base+2],DMXin[base+3]);
D_checkT=millis()+D_CHECKT;
}
}
//Serial.print(D_State,BIN);Serial.println();
}
void DMXCheck(void)
{
// CHSV hsv;
// CRGB rgb;
short t,tch;
//Here code for semi-immediate update
for (t=1,tch=0; t<=8 ; t<<=1,tch++)
if (D_State & t)
{
// Serial.print(D_State,BIN);Serial.print(":");
D_State &= ~t;
for (short trh=0; trh<4 ; trh++)
DMXSemiImmediateUpdate(tch,trh,DMXin[tch*4+trh]);
}
if ((millis()<D_checkT) || (D_checkT==0)) return;
D_checkT=0;
// Here code for network update
//int ch = 0;
DMXput();
for (int i=1; i<17; i++) {Serial.print(DMXSerial.read(i));Serial.print(";");}
Serial.println();
}
void onDmxFrame(uint16_t universe, uint16_t length, uint8_t sequence, uint8_t* data)
{
for (int i = 0 ; i < length && i<MAX_CHANNELS ; i++)
{
DmxSimple.write(i+1,data[i]);
}
}
void DMXinSetup(int channels)
{
// //Use digital pin 3 for DMX output. Must be a PWM channel.
// DmxSimple.usePin(pin);
//DmxSimple.maxChannel(channels);
DMXin = new uint8_t [channels];
DMXSerial.init(DMXReceiver,0,channels);
if (DMXSerial.getBuffer()) {Serial.print(F("Init in ch:"));Serial.println(channels);} else Serial.println(F("DMXin Buffer alloc err"));
//DMXSerial.maxChannel(channels);
DMXSerial.attachOnUpdate(&DMXUpdate);
// this will be called for each packet received
if (artnet) artnet->setArtDmxCallback(onDmxFrame);
}
void ArtnetSetup()
{
if (!artnet) artnet = new Artnet;
// this will be called for each packet received
if (artnet) artnet->setArtDmxCallback(onDmxFrame);
}

25
dmx.h Normal file
View File

@@ -0,0 +1,25 @@
#define D_UPDATED1 1
#define D_UPDATED2 2
#define D_UPDATED3 4
#define D_UPDATED4 8
#define D_CHECKT 300
#define MAX_CHANNELS 60
//define MAX_IN_CHANNELS 16
//#define DMX_OUT_PIN 3
#include <DmxSimple.h>
#include <Artnet.h>
#include <DMXSerial.h>
#include "aJSON.h"
extern aJsonObject *dmxArr;
extern Artnet *artnet;
void DMXput(void);
void DMXinSetup(int channels);
void ArtnetSetup();
void DMXCheck(void);
int itemCtrl2(char* name,int r,int g, int b, int w);

127
inputs.cpp Normal file
View File

@@ -0,0 +1,127 @@
#include "inputs.h"
#include "aJSON.h"
#include "item.h"
#include <PubSubClient2.h>
extern PubSubClient client;
Input::Input(char * name) //Constructor
{
if (name)
inputObj= aJson.getObjectItem(inputs, name);
else inputObj=NULL;
Parse();
}
Input::Input(int pin) //Constructor
{
// TODO
}
Input::Input(aJsonObject * obj) //Constructor
{
inputObj= obj;
Parse();
}
boolean Input::isValid ()
{
return (pin && store);
}
void Input::Parse()
{
store = NULL;
inType = 0;
pin = 0;
if (inputObj && (inputObj->type==aJson_Object))
{
aJsonObject * s;
s = aJson.getObjectItem(inputObj,"T");
if (s) inType = s->valueint;
pin = atoi(inputObj->name);
s = aJson.getObjectItem(inputObj,"S");
if (!s) { Serial.print("In: ");Serial.print(pin);Serial.print("/");Serial.println(inType);
aJson.addNumberToObject(inputObj,"S", 0);
s = aJson.getObjectItem(inputObj,"S");
}
if (s) store= (inStore *) &s->valueint;
}
}
int Input::Pool ()
{
boolean v;
if (!isValid()) return -1;
if (inType & IN_ACTIVE_HIGH)
{ pinMode(pin, INPUT);
v = (digitalRead(pin)==HIGH);
}
else
{ pinMode(pin, INPUT_PULLUP);
v = (digitalRead(pin)==LOW);
}
if (v!=store->cur) // value changed
{
if (store->bounce) store->bounce--;
else //confirmed change
{
Changed(v);
store->cur=v;
}
}
else // no change
store->bounce=3;
return 0;
}
void Input::Changed (int val)
{
Serial.print(pin);Serial.print("=");Serial.println(val);
aJsonObject * item = aJson.getObjectItem(inputObj,"item");
aJsonObject * scmd = aJson.getObjectItem(inputObj,"scmd");
aJsonObject * rcmd = aJson.getObjectItem(inputObj,"rcmd");
aJsonObject * emit = aJson.getObjectItem(inputObj,"emit");
if (emit)
{
if (val)
{ //send set command
if (scmd) client.publish(emit->valuestring,scmd->valuestring); else client.publish(emit->valuestring,"ON");
}
else
{ //send reset command
if (rcmd) client.publish(emit->valuestring,rcmd->valuestring); else client.publish(emit->valuestring,"OFF");
}
}
if (item)
{
Item it(item->valuestring);
if (it.isValid())
{
if (val)
{ //send set command
if (scmd) it.Ctrl(txt2cmd(scmd->valuestring),0,NULL,true); else it.Ctrl(CMD_ON,0,NULL,true);
}
else
{ //send reset command
if (rcmd) it.Ctrl(txt2cmd(scmd->valuestring),0,NULL,true); else it.Ctrl(CMD_OFF,0,NULL,true);
}
}
}
}

77
inputs.h Normal file
View File

@@ -0,0 +1,77 @@
#include "aJSON.h"
#define IN_ACTIVE_HIGH 128 // High level = PUSHED/ CLOSED/ ON othervise :Low Level
#define IN_ANALOG 64 // Analog input
#define IN_RE 32 // Rotary Encoder (for further use)
#define IN_PUSH_ON 0 // PUSH - ON, Release - OFF (ovverrided by pcmd/rcmd) - DEFAULT
#define IN_PUSH_TOGGLE 1 // Every physicall push toggle logical switch on/off
// in syntaxis
// "pin": { "T":"N", "emit":"out_emit", item:"out_item", "scmd": "ON,OFF,TOGGLE,INCREASE,DECREASE", "rcmd": "ON,OFF,TOGGLE,INCREASE,DECREASE", "rcmd":"repeat_command" }
//
//Switch/Restore all
//"pin": { "T":"1", "emit":"/all", item:"local_all", "scmd": "OFF", "rcmd": "RESTORE"}
//
//Normal (not button) Switch (toggled mode)
//"pin": { "T":"1", "emit":"/light1", item:"light1", "scmd": "TOGGLE", "rcmd": "TOGGLE"}
// or
// "pin": { "T":"xx", "emit":"/light1", item:"light1"}
//Normal (not button) Switch
//"pin": { "T":"0", "emit":"/light1", item:"light1", "scmd": "ON", "rcmd": "OFF"}
// or
// "pin": { "T":"0", "emit":"/light1", item:"light1"}
//or
// "pin": { "emit":"/light1", item:"light1"}
//1-Button dimmer
//"pin": { "T":"1", "emit":"/light1", item:"light1", "scmd": "ON", srcmd:"INCREASE",rrcmd:"DECREASE", "rcmd": "OFF"}
// or
// "pin": { "T":"xx", "emit":"/light1", item:"light1"}
//2-Buttons dimmer
//"pin1": { "T":"0", "emit":"/light1", item:"light1", "scmd": "ON", repcmd:"INCREASE"}
//"pin2": { "T":"0", "emit":"/light1", item:"light1", "scmd": "OFF", repcmd:"INCREASE"}
extern aJsonObject *inputs;
typedef union
{
long int aslong;
struct
{
int8_t reserve;
int8_t logicState;
int8_t bounce;
int8_t cur;
};
} inStore;
class Input
{
public:
aJsonObject *inputObj;
uint8_t inType;
uint8_t pin;
inStore * store;
Input(int pin);
Input(aJsonObject * obj);
Input(char * name);
boolean isValid ();
void Changed (int val);
int Pool ();
protected:
void Parse();
};

553
item.cpp Normal file
View File

@@ -0,0 +1,553 @@
#include "item.h"
#include "aJSON.h"
#include <DmxSimple.h>
#include "FastLED.h"
#include <ModbusMaster.h>
#include <PubSubClient2.h>
extern int modbusSet(int addr, uint16_t _reg, int _mask, uint16_t value);
extern PubSubClient client;
//extern const char* outprefix;
const char outprefix[] PROGMEM = "/myhome/s_out/";
static unsigned long lastctrl = 0;
static aJsonObject * lastobj = NULL;
int txt2cmd (char * payload)
{
int cmd=0;
// Check for command
if (strcmp(payload,"ON")==0) cmd=CMD_ON;
else if (strcmp(payload,"OFF")==0) cmd=CMD_OFF;
else if (strcmp(payload,"REST")==0) cmd=CMD_RESTORE;
else if (strcmp(payload,"TOGGLE")==0) cmd=CMD_TOGGLE;
else if (strcmp(payload,"HALT")==0) cmd=CMD_HALT;
return cmd;
}
Item::Item(char * name) //Constructor
{
if (name)
itemArr= aJson.getObjectItem(items, name);
else itemArr=NULL;
if (isValid())
{
// Todo - avoid static enlarge for every types
for (int i=aJson.getArraySize(itemArr);i<4;i++) aJson.addItemToArray(itemArr,aJson.createItem(int(0))); //Enlarge item to 4 elements. VAL=int if no other definition in conf
itemType = aJson.getArrayItem(itemArr,I_TYPE)->valueint;
itemArg = aJson.getArrayItem(itemArr,I_ARG);
itemVal = aJson.getArrayItem(itemArr,I_VAL);
Serial.print(F(" Item:"));
Serial.println(name);
Serial.print(itemType);Serial.print(":");Serial.println(getArg());
}
}
uint8_t Item::getCmd()
{
aJsonObject *t = aJson.getArrayItem(itemArr,I_CMD);
if (t)
return t->valueint;
else return -1;
}
void Item::setCmd(uint8_t cmd)
{
aJsonObject *t = aJson.getArrayItem(itemArr,I_CMD);
if (t)
t->valueint=cmd;
}
int Item::getArg() //Return arg int or first array element if Arg is array
{ if (!itemArg) return -1;
if (itemArg->type==aJson_Int) return itemArg->valueint;
else if (itemArg->type==aJson_Array) return aJson.getArrayItem(itemArg,0)->valueint;
else return -2;
}
/*
int Item::getVal(short n) //Return Val from Value array
{ if (!itemVal) return -1;
else if (itemVal->type==aJson_Array)
{
aJsonObject *t = aJson.getArrayItem(itemVal,n);
if (t) return t->valueint;
else return -3;
}
else return -2;
}
*/
long int Item::getVal() //Return Val if val is int or first elem of Value array
{ if (!itemVal) return -1;
if (itemVal->type==aJson_Int) return itemVal->valueint;
else if (itemVal->type==aJson_Array)
{
aJsonObject *t = aJson.getArrayItem(itemVal,0);
if (t) return t->valueint;
else return -3;
}
else return -2;
}
/*
void Item::setVal(short n, int par) // Only store if VAL is array defined in config to avoid waste of RAM
{
if (!itemVal || itemVal->type!=aJson_Array) return;
Serial.print(F(" Store p="));Serial.print(n);Serial.print(F(" Val="));Serial.println(par);
for (int i=aJson.getArraySize(itemVal);i<=n;i++) aJson.addItemToArray(itemVal,aJson.createItem(int(0))); //Enlarge array of Values
aJsonObject *t = aJson.getArrayItem(itemVal,n);
if (t) t->valueint=par;
}
*/
void Item::setVal(long int par) // Only store if VAL is int (autogenerated or config-defined)
{
if (!itemVal || itemVal->type!=aJson_Int) return;
Serial.print(F(" Store "));Serial.print(F(" Val="));Serial.println(par);
itemVal->valueint=par;
}
boolean Item::isValid ()
{
return (itemArr && (itemArr->type==aJson_Array));
}
/*
void Item::copyPar (aJsonObject *itemV)
{ int n=aJson.getArraySize(itemV);
//for (int i=aJson.getArraySize(itemVal);i<n;i++) aJson.addItemToArray(itemVal,aJson.createItem(int(0))); //Enlarge array of Values
for (int i=0;i<n;i++) setPar(i,aJson.getArrayItem(itemV,i)->valueint);
}
*/
boolean Item::getEnableCMD(int delta)
{
return ((millis()-lastctrl>(unsigned long) delta) );//|| (itemArr!=lastobj));
}
int Item::Ctrl(short cmd, short n, int * Par, boolean send)
{
Serial.print(F("Cmd="));Serial.println(cmd);
//va_list vl;
int _Par[3]={0,0,0};
if (Par==NULL) Par=_Par;
int iaddr=getArg();
HSVstore st;
//Store Parameter(s) into json VAL
switch (cmd)
{
case CMD_TOGGLE:
switch (getCmd())
{
case CMD_ON:
case CMD_SET:
cmd=CMD_OFF;
break;
case CMD_OFF:
case CMD_HALT:
cmd=CMD_ON;
break;
}//switch old cmd
break;
case CMD_RESTORE:
if (itemType!=CH_GROUP) //individual threating of channels
switch (getCmd())
{ case CMD_HALT:
// Serial.print("LastCmd:");Serial.println(t);
cmd=CMD_ON;
break;
}//switch old cmd
} //switch cmd
switch (cmd)
{
case 0: //no command
setCmd(CMD_SET);
switch (itemType)
{
case CH_GROUP:
case CH_RGBW: //only if configured VAL array
st.h=Par[0];
st.s=Par[1];
st.v=Par[2];
setVal(st.aslong);
break;
case CH_DIMMER: //Everywhere, in flat VAL
case CH_MODBUS:
case CH_THERMO:
case CH_VC:
case CH_VCTEMP:
setVal(Par[0]);
}//itemtype
lastctrl=millis(); //last controlled object ond timestamp update
lastobj =itemArr;
break;
case CMD_ON: //retrive stored values
if (getCmd()!=CMD_ON)
{
st.aslong=getVal();//Serial.print("Returned getVal: ");Serial.println(st.aslong);
if (st.aslong>=0)
{
Par[0]=st.h;
Par[1]=st.s;
Par[2]=st.v;
}
for (short i=0;i<3 ;i++)
{
Serial.print(F("Restored: "));Serial.print(i);Serial.print("=");Serial.println(Par[i]);
}
setCmd(cmd);
}
else
{ //Double ON - apply special preset
switch (itemType)
{
case CH_RGBW:
Serial.println(F("White: "));
itemType=CH_WHITE;
// Par[2]=getVal(2);
// if (Par[2]<0)
Par[2]=100;
break;
}
}
break;
case CMD_OFF:
Par[0]=0;Par[1]=0;Par[2]=0;
setCmd(cmd);
break;
case CMD_HALT:
if (getCmd()!=CMD_OFF)
{
Par[0]=0;Par[1]=0;Par[2]=0;
setCmd(cmd);
Serial.print(itemType);Serial.println(" Halted");
}
}//switch cmd
/*
Serial.print("go: ");
for (short i=0;i<3 ;i++)
{
Serial.print(i);Serial.print("=");Serial.println(Par[i]);
}
*/
if (send) SendCmd(cmd,n,Par);
switch (itemType)
{
case CH_DIMMER: //Dimmed light
DmxSimple.write(iaddr, map(Par[0],0,100,0,255));
break;
case CH_RGBW: //Colour RGBW
{
int k;
DmxSimple.write(iaddr+3, k=map((100-Par[1])*Par[2],0,10000,0,255));
Serial.print(F("W:"));Serial.println(k);
}
case CH_RGB: // RGB
{
CRGB rgb= CHSV(map(Par[0],0,365,0,255),map(Par[1],0,100,0,255),map(Par[2],0,100,0,255));
DmxSimple.write(iaddr, rgb.r);
DmxSimple.write(iaddr+1, rgb.g);
DmxSimple.write(iaddr+2, rgb.b);
break; }
case CH_WHITE:
DmxSimple.write(iaddr, 0);
DmxSimple.write(iaddr+1, 0);
DmxSimple.write(iaddr+2, 0);
DmxSimple.write(iaddr+3, map(Par[2],0,100,0,255));
break;
case CH_MODBUS:
{
if ((itemArg->type == aJson_Array) && (aJson.getArraySize(itemArg)==3))
{
int _addr= aJson.getArrayItem(itemArg,0)->valueint;
int _reg = aJson.getArrayItem(itemArg,1)->valueint;
int _mask= aJson.getArrayItem(itemArg,2)->valueint;
modbusSet(_addr,_reg,_mask,map(Par[0],0,100,0,0x1f));
}
break;}
case CH_GROUP://Group
{
//aJsonObject *groupArr= aJson.getArrayItem(itemArr, 1);
if (itemArg->type==aJson_Array)
{
aJsonObject *i =itemArg->child;
while (i)
{
Item it (i->valuestring);
// it.copyPar(itemVal);
it.Ctrl(cmd,n,Par,true);
i=i->next;
} //while
} //if
} //case
break;
case CH_RELAY:
{int k;
pinMode(iaddr,OUTPUT);
digitalWrite(iaddr,k=((cmd==CMD_ON)?HIGH:LOW));
Serial.print(F("Pin:"));Serial.print(iaddr);Serial.print(F("="));Serial.println(k);
break;
case CH_THERMO:
///thermoSet(name,cmd,Par1); all cativities done - update temp & cmd
break;
case CH_PWM:
pinMode(iaddr,OUTPUT);
//timer 0 for pin 13 and 4
//timer 1 for pin 12 and 11
//timer 2 for pin 10 and 9
//timer 3 for pin 5 and 3 and 2
//timer 4 for pin 8 and 7 and 6
//prescaler = 1 ---> PWM frequency is 31000 Hz
//prescaler = 2 ---> PWM frequency is 4000 Hz
//prescaler = 3 ---> PWM frequency is 490 Hz (default value)
//prescaler = 4 ---> PWM frequency is 120 Hz
//prescaler = 5 ---> PWM frequency is 30 Hz
//prescaler = 6 ---> PWM frequency is <20 Hz
int tval = 7; // this is 111 in binary and is used as an eraser
TCCR4B &= ~tval; // this operation (AND plus NOT), set the three bits in TCCR2B to 0
TCCR3B &= ~tval;
tval=2;
TCCR4B|=tval;
TCCR3B|=tval;
analogWrite(iaddr,k=map(Par[0],0,100,0,255));
Serial.print(F("Pin:"));Serial.print(iaddr);Serial.print(F("="));Serial.println(k);
break;
}
case CH_VC:
VacomSetFan(getArg(),Par[0]);
break;
case CH_VCTEMP:
{
Item it (itemArg->valuestring);
if (it.isValid() && it.itemType==CH_VC)
VacomSetHeat(it.getArg(),Par[0],cmd);
break;
}
} // switch itemtype
// break;
}
/*
short thermoSet(char * name, short cmd, short t)
{
if (items)
{
aJsonObject *item= aJson.getObjectItem(items, name);
if (item && (item->type==aJson_Array) && (aJson.getArrayItem(item, I_TYPE)->valueint==CH_THERMO))
{
for (int i=aJson.getArraySize(item);i<4;i++) aJson.addItemToArray(item,aJson.createItem(int(0))); //Enlarge item to 4 elements
if (!cmd) aJson.getArrayItem(item, I_VAL)->valueint=t;
aJson.getArrayItem(item, I_CMD)->valueint=cmd;
}
}
}
*/
void PooledItem::Idle()
{
if (PoolingInterval)
{
Pool();
next=millis()+PoolingInterval;
}
};
/*
addr 10d
Снять аварию 42001 (2001=7d1) =>4
[22:20:33] Write task has completed successfully
[22:20:33] <= Response: 0A 06 07 D0 00 04 89 FF
[22:20:32] => Poll: 0A 06 07 D0 00 04 89 FF
100%
2003-> 10000
[22:24:05] Write task has completed successfully
[22:24:05] <= Response: 0A 06 07 D2 27 10 33 C0
[22:24:05] => Poll: 0A 06 07 D2 27 10 33 C0
ON
2001->1
[22:24:50] Write task has completed successfully
[22:24:50] <= Response: 0A 06 07 D0 00 01 49 FC
[22:24:50] => Poll: 0A 06 07 D0 00 01 49 FC
OFF
2001->0
[22:25:35] Write task has completed successfully
[22:25:35] <= Response: 0A 06 07 D0 00 00 88 3C
[22:25:34] => Poll: 0A 06 07 D0 00 00 88 3C
POOL 2101x10
[22:27:29] <= Response: 0A 03 14 00 23 00 00 27 10 13 88 0B 9C 00 32 00 F8 00 F2 06 FA 01 3F AD D0
[22:27:29] => Poll: 0A 03 08 34 00 0A 87 18
*/
int Item::Pool()
{
}
extern short modbusBusy;
extern ModbusMaster node;
int Item::VacomSetFan (int addr, int8_t val)
{
Serial.print("VC#");Serial.print(addr);Serial.print("=");Serial.println(val);
if (modbusBusy) return -1;
modbusBusy=1;
uint8_t j, result;
uint16_t data[1];
node.begin(9600,SERIAL_8N1,13);
node.setSlave(addr);
if (val) {
node.writeSingleRegister(2001-1,4+1);//delay(500);
//node.writeSingleRegister(2001-1,1);
}
else node.writeSingleRegister(2001-1,0);
delay (500);
node.writeSingleRegister(2003-1,val*100);
/*
result = node.readHoldingRegisters(2003, 10);
// do something with data if read is successful
if (result == node.ku8MBSuccess)
{ Serial.print(F(" FM Val :"));
for (j = 0; j < 10; j++)
{
data[j] = node.getResponseBuffer(j);
Serial.print(data[j],HEX);Serial.print("-");
}
Serial.println();
} else {Serial.print(F("Modbus pooling error=")); Serial.println(result,HEX); }
*/
modbusBusy=0;
}
int Item::VacomSetHeat(int addr, int8_t val, int8_t cmd)
{
Serial.print("VC#");Serial.print(addr);Serial.print("=");Serial.print(val);Serial.print(" cmd=");Serial.println(cmd);
}
int Item::SendCmd(short cmd,short n, int * Par)
{
char addrstr[32];
char addrbuf[17];
char valstr[16];
strcpy_P (addrstr,outprefix);
strncat (addrstr,itemArr->name,sizeof(addrstr)); ////
switch (cmd)
{
case CMD_ON:
strcpy(valstr,"ON");
break;
case CMD_OFF:
case CMD_HALT:
strcpy(valstr,"OFF");
break;
// TODO send Par
//case 0:
//case CMD_SET:
///////////sprintf(valstr,"%d",Par[0]);
default:
return -1;
}
Serial.print(addrstr);Serial.print("->");Serial.println(valstr);
client.publish(addrstr, valstr);
return 0;
}

102
item.h Normal file
View File

@@ -0,0 +1,102 @@
#define CH_DIMMER 0 //DMX 1 ch
#define CH_RGBW 1 //DMX 4 ch
#define CH_RGB 2 //DMX 3 ch
#define CH_PWM 3 //PWM output directly to PIN
#define CH_MODBUS 4 //Modbus AC Dimmer
#define CH_THERMO 5 //Simple ON/OFF thermostat
#define CH_RELAY 6 //ON_OFF relay output
#define CH_GROUP 7 //Group pseudochannel
#define CH_VCTEMP 8 //Vacom PID regulator
#define CH_VC 9 //Vacom modbus motor regulator
#define CH_WHITE 127//
#define CMD_ON 1
#define CMD_OFF 2
#define CMD_HALT 5
#define CMD_RESTORE 3
#define CMD_TOGGLE 4
#define CMD_CURTEMP 127
#define CMD_SET 9
#define I_TYPE 0 //Type of item
#define I_ARG 1 //Chanel-type depended argument or array of arguments (pin, address etc)
#define I_VAL 2 //Latest preset (int or array of presets)
#define I_CMD 3 //Latest CMD received
#define I_EXT 4 //Chanell-depended extension - array
#include "aJSON.h"
extern aJsonObject *items;
int txt2cmd (char * payload);
typedef union
{
long int aslong;
struct
{
int16_t h;
int8_t s;
int8_t v;
};
} HSVstore;
class Item
{
public:
aJsonObject *itemArr, *itemArg,*itemVal;
uint8_t itemType;
Item(char * name);
boolean isValid ();
virtual int Ctrl(short cmd, short n=0, int * Par=NULL, boolean send=false);
int getArg();
boolean getEnableCMD(int delta);
//int getVal(short n); //From VAL array. Negative if no array
long int getVal(); //From int val OR array
uint8_t getCmd();
void setCmd(uint8_t cmd);
//void setVal(uint8_t n, int par);
void setVal(long int par);
//void copyPar (aJsonObject *itemV);
inline int On (){Ctrl(CMD_ON);};
inline int Off(){Ctrl(CMD_OFF);};
inline int Toggle(){Ctrl(CMD_TOGGLE);};
int Pool ();
int SendCmd(short cmd,short n=0, int * Par=NULL);
protected:
int VacomSetFan (int addr, int8_t val);
int VacomSetHeat(int addr, int8_t val, int8_t cmd=0);
};
class PooledItem : public Item
{
public:
virtual int Changed() = 0;
virtual void Idle ();
protected:
int PoolingInterval;
unsigned long next;
virtual int Pool() =0;
};
/*
class Vacon : public Item
{
public:
int Pool ();
virtual int Ctrl(short cmd, short n=0, int * Par=NULL);
protected:
};
*/

1061
lighthub.ino Normal file

File diff suppressed because it is too large Load Diff

438
owSwitch.cpp Normal file
View File

@@ -0,0 +1,438 @@
#include "owSwitch.h"
#include "owTerm.h"
#include <Arduino.h>
#include "utils.h"
int owRead2408(uint8_t* addr) {
uint8_t buf[13];
// PrintBytes(buf, 13, true);
if (!net) return -1;
net->reset();
net->select(addr);
// uint8_t buf[13]; // Put everything in the buffer so we can compute CRC easily.
buf[0] = 0xF0; // Read PIO Registers
buf[1] = 0x88; // LSB address
buf[2] = 0x00; // MSB address
net->write_bytes(buf, 3,1);
net->read_bytes(buf+3, 10); // 3 cmd bytes, 6 data bytes, 2 0xFF, 2 CRC16
net->reset();
if (!OneWire::check_crc16(buf, 11, &buf[11])) {
Serial.print(F("CRC failure in DS2408 at "));
PrintBytes(addr, 8, true);
PrintBytes(buf+3,10);
return -1;
}
return (buf[3]);
}
/*
int read1W(int i)
{
Serial.print("1W requested: ");
Serial.println (i);
int t=-1;
switch (term[i][0]){
case 0x29: // DS2408
t=owRead2408(term[i]);
break;
case 0x28: // Thermomerer
t=sensors.getTempC(term[i]);
}
return t;
}
*/
int ow2408out(DeviceAddress addr,uint8_t cur)
{
if (!net) return -1;
uint8_t buf[5];
net->reset();
net->select(addr);
buf[0] = 0x5A; // Write PIO Registers
buf[1]=cur;
buf[2] = ~buf[1];
net->write_bytes(buf, 3);
net->read_bytes(buf+3, 2);
//net.reset();
PrintBytes(buf, 5);
Serial.print(" Out: ");Serial.print(buf[1],BIN);
Serial.print(" In: ");Serial.println(buf[4],BIN);
if (buf[3] != 0xAA) {
Serial.print("Write failure in DS2408 at ");
PrintBytes(addr, 8, true);
return -2;
}
return buf[4];
}
int cntrl2408(uint8_t* addr, int subchan, int val) {
if (!net) return -1;
uint8_t buf;
int mask,devnum;
if ((devnum=owFind(addr))<0) return -1;
buf=regs[devnum];
Serial.print("Current: ");Serial.println(buf,BIN);
mask=0;
int r,f;
switch (subchan) {
case 0:
if ((buf & SW_STAT0) != ((val)?SW_STAT0:0))
{
if (wstat[devnum] & (SW_PULSE0|SW_PULSE_P0))
{
wstat[devnum]|=SW_CHANGED_P0;
Serial.println("Rollback 0");
}
else {
wstat[devnum]|=SW_PULSE0;
regs[devnum] = (ow2408out(addr,(buf | SW_MASK) & ~SW_OUT0) & SW_INMASK) ^ SW_STAT0; ///?
}
}
return 0;
case 1:
if ((buf & SW_STAT1) != ((val)?SW_STAT1:0))
{
if (wstat[devnum] & (SW_PULSE1|SW_PULSE_P1))
{
wstat[devnum]|=SW_CHANGED_P1;
Serial.println("Rollback 1");
}
else {
wstat[devnum]|=SW_PULSE1;
regs[devnum] =(ow2408out(addr,(buf | SW_MASK) & ~SW_OUT1) & SW_INMASK) ^ SW_STAT1; /// -?
}
}
return 0;
/* Assume AUX 0&1 it is INPUTS - no write
case 2:
mask=SW_AUX0;
break;
case 3:
mask=SW_AUX1; */
}
/* Assume AUX 0&1 it is INPUTS - no write
switch (val) {
case 0: buf=(buf | SW_MASK | SW_OUT0 | SW_OUT1) | mask;
break;
default: buf= (buf | SW_MASK | SW_OUT0 | SW_OUT1) & ~mask;
}
regs[devnum] = ow2408out(addr,buf); */
return 0;
}
int cntrl2890(uint8_t* addr, int val) {
uint8_t buf[13];
if (!net) return -1;
// case 0x2C: //Dimmer
Serial.print("Update dimmer ");PrintBytes(addr, 8, true);Serial.print(" = ");
Serial.println(val);
net->reset();
net->select(addr);
buf[0] = 0x55;
buf[1] = 0x4c;
net->write_bytes(buf, 2);
net->read_bytes(buf+2, 1); // check if buf[2] == val = ok
buf[3]=0x96;
net->write_bytes(buf+3, 1);
net->read_bytes(buf+4, 1); // 0 = updated ok
PrintBytes(buf, 5, true);
net->select(addr);
if (val==-1)
{
buf[0] = 0xF0;
net->write_bytes(buf, 1);
net->read_bytes(buf+1, 2); // check if buf[2] == val = ok
net->reset();
return buf[2];
}
else
{
buf[0] = 0x0F;
buf[1] = val;
net->write_bytes(buf, 2);
net->read_bytes(buf+2, 1); // check if buf[2] == val = ok
buf[3]=0x96;
net->write_bytes(buf+3, 1);
net->read_bytes(buf+4, 1); // 0 = updated ok
net->reset();
PrintBytes(buf, 5, true);
return buf[2];
}
}
#define DS2413_FAMILY_ID 0x3A
#define DS2413_ACCESS_READ 0xF5
#define DS2413_ACCESS_WRITE 0x5A
#define DS2413_ACK_SUCCESS 0xAA
#define DS2413_ACK_ERROR 0xFF
#define DS2413_IN_PinA 1
#define DS2413_IN_LatchA 2
#define DS2413_IN_PinB 4
#define DS2413_IN_LatchB 8
#define DS2413_OUT_PinA 1
#define DS2413_OUT_PinB 2
/*
byte read(void)
{
bool ok = false;
uint8_t results;
oneWire.reset();
oneWire.select(address);
oneWire.write(DS2413_ACCESS_READ);
results = oneWire.read(); / Get the register results /
ok = (!results & 0x0F) == (results >> 4); / Compare nibbles /
results &= 0x0F; / Clear inverted values /
oneWire.reset();
// return ok ? results : -1;
return results;
}
bool write(uint8_t state)
{
uint8_t ack = 0;
/ Top six bits must '1' /
state |= 0xFC;
oneWire.reset();
oneWire.select(address);
oneWire.write(DS2413_ACCESS_WRITE);
oneWire.write(state);
oneWire.write(~state); / Invert data and resend /
ack = oneWire.read(); / 0xAA=success, 0xFF=failure /
if (ack == DS2413_ACK_SUCCESS)
{
oneWire.read(); / Read the status byte /
}
oneWire.reset();
return (ack == DS2413_ACK_SUCCESS ? true : false);
}
*/
int cntrl2413(uint8_t* addr, int subchan, int val) {
bool ok = false;
uint8_t results;
uint8_t cmd;
uint8_t set=0;
uint8_t count =10;
if (!net) return -1;
// case 0x85: //Switch
Serial.print("Update switch ");PrintBytes(addr, 8, false); Serial.print("/");Serial.print(subchan);Serial.print(" = ");Serial.println(val);
while (count--)
{
net->reset();
net->select(addr);
net->setStrongPullup();
cmd = DS2413_ACCESS_READ;
net->write(cmd);
results = net->read();
Serial.print("Got: "); Serial.println(results,BIN);
//Serial.println((~results & 0x0F),BIN); Serial.println ((results >> 4),BIN);
ok = (~results & 0x0F) == (results >> 4); // Compare nibbles
results &= 0x0F; // Clear inverted values
if (ok) {Serial.println("Read ok");break;} else {Serial.println("read Error");delay(1);}
} //while
if (ok && (val>=0))
{
count=10;
while (count--)
{
net->reset();
net->select(addr);
if (results & DS2413_IN_LatchA) set|=DS2413_OUT_PinA;
if (results & DS2413_IN_LatchB) set|=DS2413_OUT_PinB;
switch (subchan) {
case 0:
if (!val) set|=DS2413_OUT_PinA; else set &= ~DS2413_OUT_PinA;
break;
case 1:
if (!val) set|=DS2413_OUT_PinB; else set &= ~DS2413_OUT_PinB;
};
set |= 0xFC;
Serial.print("New: ");Serial.println(set,BIN);
cmd = DS2413_ACCESS_WRITE;
net->write(cmd);
net->write(set);
net->write(~set);
uint8_t ack = net->read(); // 0xAA=success, 0xFF=failure
if (ack == DS2413_ACK_SUCCESS)
{
results=net->read();
Serial.print("Updated ok: "); Serial.println(results,BIN);
ok = (~results & 0x0F) == (results >> 4); // Compare nibbles
{
if (ok)
{Serial.println("Readback ok");
break;}
else {Serial.println("readback Error");delay(1);}
}
results &= 0x0F; // Clear inverted values
}
else Serial.println ("Write failed");;
} //while
} //if
return ok ? results : -1;
}
int sensors_ext(void)
{
int t;
switch (term[si][0]){
case 0x29: // DS2408
//Serial.println(wstat[si],BIN);
if (wstat[si] & SW_PULSE0) {
wstat[si]&=~SW_PULSE0;
wstat[si]|=SW_PULSE_P0;
Serial.println("Pulse0 in progress");
return 500;
}
if (wstat[si] & SW_PULSE0_R) {
wstat[si]&=~SW_PULSE0_R;
wstat[si]|=SW_PULSE_P0;
regs[si] =(ow2408out(term[si],(regs[si] | SW_MASK) & ~SW_OUT0) & SW_INMASK) ^ SW_STAT0;
Serial.println("Pulse0 in activated");
return 500;
}
if (wstat[si] & SW_PULSE1) {
wstat[si]&=~SW_PULSE1;
wstat[si]|=SW_PULSE_P1;
Serial.println("Pulse1 in progress");
return 500;
}
if (wstat[si] & SW_PULSE1_R) {
wstat[si]&=~SW_PULSE1_R;
wstat[si]|=SW_PULSE_P1;
regs[si] =(ow2408out(term[si],(regs[si] | SW_MASK) & ~SW_OUT1) & SW_INMASK) ^ SW_STAT1;
Serial.println("Pulse0 in activated");
return 500;
}
if (wstat[si] & SW_PULSE_P0) {
wstat[si]&=~SW_PULSE_P0;
Serial.println("Pulse0 clearing");
ow2408out(term[si],regs[si] | SW_MASK | SW_OUT0);
if (wstat[si] & SW_CHANGED_P0) {
wstat[si]&=~SW_CHANGED_P0;
wstat[si]|=SW_PULSE0_R;
return 500;
}
}
if (wstat[si] & SW_PULSE_P1) {
wstat[si]&=~SW_PULSE_P1;
Serial.println("Pulse1 clearing");
ow2408out(term[si],regs[si] | SW_MASK | SW_OUT1);
if (wstat[si] & SW_CHANGED_P1) {
wstat[si]&=~SW_CHANGED_P1;
wstat[si]|=SW_PULSE1_R;
return 500;
}
}
if (wstat[si])
{
t=owRead2408(term[si]) & SW_INMASK;
if (t!=regs[si]) {
Serial.print(F("DS2408 data = "));
Serial.println(t, BIN);
if (!(wstat[si] & SW_DOUBLECHECK))
{
wstat[si]|=SW_DOUBLECHECK; //suspected
Serial.println("DOUBLECHECK");
return recheck_interval;
}
Serial.println(F("Really Changed"));
if (owChanged) owChanged(si,term[si],t);
regs[si]=t;
}
wstat[si]&=~SW_DOUBLECHECK;
}
break;
case 0x01:
case 0x81:
t=wstat[si];
if (t!=regs[si])
{ Serial.println("Changed");
if (owChanged) owChanged(si,term[si],t);
regs[si]=t;
}
}
si++;
return check_circle;
}

12
owSwitch.h Normal file
View File

@@ -0,0 +1,12 @@
//define APU_OFF
#include <OneWire.h>
#include <DallasTemperature.h>
int owRead2408(uint8_t* addr);
int ow2408out(DeviceAddress addr,uint8_t cur);
//int read1W(int i);
int cntrl2408(uint8_t* addr, int subchan, int val=-1);
int cntrl2413(uint8_t* addr, int subchan, int val=-1);
int cntrl2890(uint8_t* addr, int val);

177
owTerm.cpp Normal file
View File

@@ -0,0 +1,177 @@
#include "owTerm.h"
#include <Arduino.h>
#include "utils.h"
OneWire *net = NULL;
// Pass our oneWire reference to Dallas Temperature.
//DallasTemperature sensors(&net);
DeviceAddress *term = NULL;
//int *regs = NULL;
uint16_t *wstat = NULL;
DallasTemperature *sensors = NULL;
short si=0;
int t_count = 0;
unsigned long owTimer=0;
owChangedType owChanged;
int owUpdate()
{
unsigned long finish = millis() + 5000;
short sr;
//net.setStrongPullup();
Serial.println(F("Searching"));
if (net) net->reset_search();
for (short i=0;i<t_count;i++) wstat[i]&=~SW_FIND; //absent
while (net && net->wireSearch(term[t_count])>0 && (t_count<t_max) && finish > millis ())
{ short ifind=-1;
if (net->crc8(term[t_count], 7) == term[t_count][7])
{
for (short i=0;i<t_count;i++) if (!memcmp(term[i],term[t_count],8)) {ifind=i;wstat[i]|=SW_FIND;
Serial.print(F(" Node:"));PrintBytes(term[t_count],8);Serial.println(F(" alive"));
break;}; //alive
if (ifind<0 && sensors)
{
wstat[t_count]=SW_FIND; //Newly detected
Serial.print(F("dev#"));Serial.print(t_count);Serial.print(F(" Addr:"));PrintBytes(term[t_count],8);
Serial.println();
if (term[t_count][0]==0x28)
{
sensors->setResolution(term[t_count], TEMPERATURE_PRECISION);
net->setStrongPullup();
// sensors.requestTemperaturesByAddress(term[t_count]);
}
t_count++;}
}//if
} //while
Serial.print(F("1-wire count: "));
Serial.println(t_count);
}
int owSetup(owChangedType owCh) {
//// todo - move memory allocation to here
#ifdef _2482
net = new OneWire;
#else
net = new OneWire (ONE_WIRE_BUS);
#endif
// Pass our oneWire reference to Dallas Temperature.
sensors = new DallasTemperature (net);
term = new DeviceAddress[t_max];
//regs = new int [t_max];
wstat = new uint16_t [t_max];
#ifdef _2482
Wire.begin();
if (net->checkPresence())
{
Serial.println(F("DS2482-100 present"));
net->deviceReset();
#ifdef APU_OFF
Serial.println(F("APU off"));
#else
net->setActivePullup();
#endif
Serial.println(F("\tChecking for 1-Wire devices..."));
if (net->wireReset())
Serial.println(F("\tReset done"));
sensors->begin();
owChanged=owCh;
//owUpdate();
//Serial.println(F("\t1-w Updated"));
sensors->setWaitForConversion(false);
return true;
}
#endif
return false;
// IC Default 9 bit. If you have troubles consider upping it 12. Ups the delay giving the IC more time to process the temperature measurement
delay(500);
}
int sensors_loop(void)
{
if (!sensors) return -1;
if (si>=t_count)
{
owUpdate(); //every check circle - scan for new devices
si=0;
return 8000;
}
int t;
switch (term[si][0]){
case 0x28: // Thermomerer
t=sensors->getTempC(term[si]);//*10.0;
//Serial.println("o");
if (owChanged) owChanged(si,term[si],t);
sensors->requestTemperaturesByAddress(term[si]);
si++;
return 2500;
// default
// return sensors_ext();
} //switch
si++;
return check_circle;
}
void owLoop()
{
if (millis() >=owTimer) owTimer=millis()+sensors_loop();
}
int owFind(DeviceAddress addr)
{
for (short i=0;i<t_count;i++) if (!memcmp(term[i],addr,8)) return i;//find
return -1;
}
void owAdd (DeviceAddress addr)
{
wstat[t_count]=SW_FIND; //Newly detected
memcpy (term[t_count],addr,8);
//term[t_count]=addr;
Serial.print(F("dev#"));Serial.print(t_count);Serial.print(F(" Addr:"));PrintBytes(term[t_count],8);
Serial.println();
if (term[t_count][0]==0x28)
{
sensors->setResolution(term[t_count], TEMPERATURE_PRECISION);
net->setStrongPullup();
// sensors.requestTemperaturesByAddress(term[t_count]);
}
t_count++;
}

70
owTerm.h Normal file
View File

@@ -0,0 +1,70 @@
//define APU_OFF
#define SW_AUX0 0x40
#define SW_AUX1 0x80
#define SW_STAT0 0x4
#define SW_STAT1 0x8
#define SW_OUT0 0x20
#define SW_OUT1 0x10
#define SW_MASK 0xF
#define SW_INMASK 0xFC
#define recheck_interval 5
#define check_circle 2000/t_count
#define SW_FIND 1
#define SW_DOUBLECHECK 2 //Doublecheck required
#define SW_PULSE0 4 //Pulse Reset started
#define SW_PULSE1 8 //Pulse Reset stsrted
#define SW_PULSE_P0 0x10 //Pulse reset in process
#define SW_PULSE_P1 0x20 //Pulse reset in process
#define SW_CHANGED_P0 0x40 //Changes while pulse in progress
#define SW_CHANGED_P1 0x80 //Changes while pulse in progress
#define SW_PULSE0_R 0x100 //Pulse Reset requested
#define SW_PULSE1_R 0x200 //Pulse Reset requested
#define recheck_interval 5
#define check_circle 2000/t_count
#define t_max 20 //Maximum number of 1w devices
#define TEMPERATURE_PRECISION 9
#include <OneWire.h>
#include <DallasTemperature.h>
#include "aJSON.h"
extern aJsonObject *owArr;
typedef void (*owChangedType) (int , DeviceAddress, int) ;
#define _2482 // HW driver
#ifdef _2482
#include <Wire.h>
#else
#define ONE_WIRE_BUS A0
#endif
extern OneWire *net;
extern DallasTemperature *sensors;
extern DeviceAddress *term ;
extern int *regs ;
extern uint16_t *wstat;
extern int t_count;
extern short si;
extern owChangedType owChanged;
int owUpdate();
int owSetup(owChangedType owCh);
void owLoop();
void owIdle(void) ;
int owFind(DeviceAddress addr);
void owAdd (DeviceAddress addr);

41
utils.cpp Normal file
View File

@@ -0,0 +1,41 @@
#include "utils.h"
void PrintBytes(uint8_t* addr, uint8_t count, bool newline) {
for (uint8_t i = 0; i < count; i++) {
Serial.print(addr[i]>>4, HEX);
Serial.print(addr[i]&0x0f, HEX);
}
if (newline)
Serial.println();
}
const char HEXSTR[]="0123456789ABCDEF";
void SetBytes(uint8_t* addr, uint8_t count, char * out) {
// Serial.println("SB:");
for (uint8_t i = 0; i < count; i++) {
*(out++)=HEXSTR[(addr[i]>>4)];
*(out++)=HEXSTR[(addr[i]&0x0f)];
}
*out=0;
}
byte HEX2DEC(char i)
{ byte v;
if ('a' <= i && i <='f') { v=i-97+10; }
else if ('A' <= i && i <='F') { v=i-65+10; }
else if ('0' <= i && i <='9') { v=i-48; }
return v;
}
void SetAddr(char * out, uint8_t* addr) {
for (uint8_t i = 0; i < 8; i++) {
*addr=HEX2DEC(*out++)<<4;
*addr++|=HEX2DEC(*out++);
}
}

5
utils.h Normal file
View File

@@ -0,0 +1,5 @@
#include <Arduino.h>
void PrintBytes(uint8_t* addr, uint8_t count, bool newline=0);
void SetBytes(uint8_t* addr, uint8_t count, char * out);
void SetAddr(char * out, uint8_t* addr);
uint8_t HEX2DEC(char i);