Important Input re-intrance bug fixed

Haier AC relability improved (buffer not save if incoming packet broken)
CAN - sub-item calculation fixed
continue working on MultiAC
config for LH board testing shared
This commit is contained in:
2025-06-26 14:07:23 +03:00
parent 9989e3db21
commit d71499442e
14 changed files with 343 additions and 86 deletions

View File

@@ -45,4 +45,5 @@
#HAL_ETH_MODULE_DISABLED #HAL_ETH_MODULE_DISABLED
#HAL_SD_MODULE_DISABLED #HAL_SD_MODULE_DISABLED
#HAL_DAC_MODULE_DISABLED #HAL_DAC_MODULE_DISABLED
#-DMERCURY_ENABLE #-DMERCURY_ENABLE
-D ROTARYENCODER

View File

@@ -1,3 +1,3 @@
export PORT=cu.usbmodem144101 export PORT=cu.usbmodem142401
echo . | stty -f /dev/$PORT speed 1200 echo . | stty -f /dev/$PORT speed 1200
../tools/mac/tool-bossac/bossac -U false -p $PORT -i -w -v -b firmware.bin -R ../tools/mac/tool-bossac/bossac -U false -p $PORT -i -w -v -b firmware.bin -R

View File

@@ -1 +1 @@
../tools/mac/arduinoOTA -address 192.168.11.13 -port 80 -username arduino -password password -sketch firmware.bin -b -upload /sketch ../tools/mac/arduinoOTA -address 192.168.11.200 -port 80 -username arduino -password password -sketch firmware.bin -b -upload /sketch

View File

@@ -0,0 +1,221 @@
{
"dmx":[3,60],
"mqtt":["lh22-test","192.168.11.4"],
"dmxin":["led5","led6","led7","led8"],
"topics":{"root":"test2"},
"syslog":["192.168.88.2"],
"ow":{
"282F7E81E3713C59":{"emit":"t_1"}
},
"modbus":
{
"s8":{
"poll":{"irs":[[0,3]],"regs":[[0,1],31],"delay":11000},
"par":{
"co2":{"ir":3},
"meterStat":{"ir":0},
"alarmStat":{"ir":1},
"hr1":{"reg":0},
"hr2":{"reg":1},
"hr32":{"reg":31}
}
},
"term":{
"poll":{"regs":[0],"delay":12000},
"par":{
"t":{"reg":0,"type":"x10"}
}
},
"thmeter":{
"serial":"8N1",
"baud":4800,
"poll":{"regs":[[0,1],[2000,2001],[80,81]],"delay":3000},
"par":{
"hum" :{"reg":0,"type":"x10"},
"temp" :{"reg":1,"type":"x10"},
"slaveid" :{"reg":2000},
"baud" :{"reg":2001},
"tcalib":{"reg":80,"type":"x10"},
"hcalib":{"reg":81,"type":"x10"}
}
},
"panel":{
"serial":"8E1",
"poll":{"regs":[[39993,40008],[30000,30001]],"delay":5000},
"par":{
"fanspeed" :{"reg":40000,"prefetch":true,"map":{"val":[1,255,1,5],"cmd":[["OFF",0]]},"id":7},
"settemp" :{"reg":40002,"prefetch":true,"id":12},
"alm01":{"reg":40004,"id":13},
"alm17":{"reg":40005,"id":14},
"alm33":{"reg":40006,"id":15},
"sethum" :{"reg":40007,"prefetch":true,"id":16},
"setvoc" :{"reg":40008,"prefetch":true,"map":{"val":[400,2000,0,100]},"id":17},
"roomtemp" :{"reg":30000,"type":"x10"},
"hum" :{"reg":30001},
"voc" :{"reg":30002},
"ch_temp" :{"reg":40009,"type":"x10","id":3},
"ext_temp" :{"reg":40010,"type":"x10","id":18},
"out_temp" :{"reg":40011,"type":"x10","id":19},
"floor_temp" :{"reg":40012,"type":"x10","id":20},
"ch_hum" :{"reg":40013,"id":28},
"heat_pwr":{"reg":40014,"id":29},
"extvoc":{"reg":40015,"map":{"val":[400,2000,0,100]},"id":27},
"actemp":{"reg":40016,"type":"x10","id":25},
"fanlvl":{"reg":40017,"id":21},
"floormode":{"reg":39995,"prefetch":true,"id":22},
"setfloor":{"reg":39996,"prefetch":true,"id":23},
"humpwr":{"reg":39998,"prefetch":true,"map":{"cmd":[null,["ON",1],["OFF",0]],"val":null},"id":24},
"fanauto":{"reg":39999,"prefetch":true,"map":{"cmd":[["ENABLE",1],["DISABLE",0],["AUTO",1]],"val":null},"id":7},
"acsettemp":{"reg":39994,"prefetch":true,"id":26},
"acon":{"reg":40003,"prefetch":true,"map":{"cmd":[1,["OFF",0]],"val":null,"def":40001},"id":8},
"acmode" :{"reg":40001,"prefetch":true,"map":{"cmd":[["FAN_ONLY",1],["HEAT",4],["COOL",2],["AUTO",8]]},"id":8},
"acfanauto":{"reg":39993,"prefetch":true,"map":{"cmd":[0,["AUTO",1]],"val":null,"def":39997},"id":2},
"acfan":{"reg":39997,"prefetch":true,"map":{"cmd":[["OFF",0],["LOW",1],["HIGH",3],["MEDIUM",2]]},"id":2},
"y":{"reg":65512},
"mo":{"reg":65513},
"d":{"reg":65514},
"dw":{"reg":65515},
"h":{"reg":65516},
"m":{"reg":65517},
"s":{"reg":65518},
"blmind":{"reg":50051},
"blmaxd":{"reg":50052},
"blminn":{"reg":50053},
"blmaxn":{"reg":50054}
}
}
},
"items": {
"th":[14,[1,"thmeter",
{
"temp":{"emit":"temp","@S":null},
"hum" :{"emit":"zal2hum","@S":null},
"slaveid" :{"emit":"slaveid"},
"baud" :{"emit":"baud"},
"tcalib":{"emit":"tcalib"},
"hcalib":{"emit":"hcalib"}
}
]],
"pout0":[6,22],
"pout1":[6,23],
"pout2":[6,24],
"pout3":[6,25],
"pout4":[3,9],
"pout5":[3,8],
"pout6":[3,11],
"pout7":[3,12],
"pwm0" :[3,4],
"pwm1" :[3,5],
"pwm2" :[3,6],
"pwm3" :[3,7],
"unprot0":[6,33],
"unprot1":[6,32],
"unprot2":[6,31],
"unprot3":[6,30],
"unprot4":[6,29],
"unprot5":[6,28],
"unprot6":[6,27],
"unprot7":[6,26],
"led": [1,1],
"led2":[1,5],
"led3":[1,9],
"led4":[1,13],
"led5":[1,17],
"led6":[1,21],
"led7":[1,25],
"led8":[1,29],
"dimmer" :[0,33],
"dimmer2":[0,34],
"dimmer3":[0,35],
"dimmer4":[0,36],
"dimmer5":[0,37],
"dimmer6":[0,38],
"dimmers":[7,["dimmer","dimmer2","dimmer3","dimmer4","dimmer5","dimmer6"]],
"leds":[7,["led","led2","led3","led4","led5","led6"]],
"mbuses":[7,["mbusdim1","mbusdim2","mbusdim3","mbusdim4"]],
"all":[7,["dimmers","uouts","relays","leds"]],
"relays":[7,["pout0","pout1","pout2","pout3","pout4","pout5","pout6","pout7"]],
"uouts":[7,["unprot0","unprot1","unprot2","unprot3","unprot4","unprot5","unprot6","unprot7"]]
},
"in":{
"42":{"emit":"in0"},
"44":{"emit":"in1"},
"46":{"emit":"in2"},
"49":{"emit":"in3"},
"43":{"emit":"in4"},
"45":{"emit":"in5"},
"47":{"emit":"in6"},
"48":{"emit":"in7"},
"34":{"emit":"in8"},
"36":{"emit":"in9"},
"38":{"emit":"in10"},
"40":{"emit":"in11"},
"35":{"emit":"in12"},
"37":{"emit":"in13"},
"39":{"emit":"in14"},
"41":{"emit":"in15"},
"54":{"T":64,"emit":"a00","item":"water","map":[200,700],"scmd":"ON","rcmd":"OFF"},
"55":{"T":64,"emit":"a01","item":"water","map":[200,700],"scmd":"ON","rcmd":"OFF"},
"56":{"T":64,"emit":"a02","map":[0,1024,0,1024,10]},
"57":{"T":64,"emit":"a03","map":[0,1024,0,1024,10]},
"58":{"T":64,"emit":"a04","map":[0,1024,0,1024,10]},
"59":{"T":64,"emit":"a05","map":[0,1024,0,1024,10]},
"60":{"T":64,"emit":"a06"},
"61":{"T":64,"emit":"a07","map":[0,1024,0,1024,5]},
"62":{"T":64,"emit":"a08","map":[0,1024,0,1024,5]},
"63":{"T":64,"emit":"a09","map":[0,1024,0,1024,5]},
"64":{"T":64,"emit":"a10","map":[0,1024,0,1024,5]},
"65":{"T":64,"emit":"a11","map":[0,1024,0,1024,5]},
"66":{"T":2,"emit":"d12"},
"67":{
"T":2,
"scmd":{"emit":"d13","ecmd":"scmd"},
"rcmd":{"emit":"d13","ecmd":"rcmd"},
"lcmd":{"emit":"d13","ecmd":"lcmd"},
"click":{"emit":"d13","ecmd":"click"},
"dclick":{"emit":"d13","ecmd":"dclick"},
"tclick":{"emit":"d13","ecmd":"tclick"},
"scmd2":{"emit":"d13","ecmd":"scmd2"},
"scmd3":{"emit":"d13","ecmd":"scmd3"},
"lcmd2":{"emit":"d13","ecmd":"lcmd2"},
"lcmd3":{"emit":"d13","ecmd":"lcmd3"},
"rpcmd":{"emit":"d13","ecmd":"rpcmd"},
"rpcmd2":{"emit":"d13","ecmd":"rpcmd2"},
"rpcmd3":{"emit":"d13","ecmd":"rpcmd3"}
},
"68":{"T":2,
"scmd":{"emit":"d14","ecmd":"scmd"},
"rcmd":{"emit":"d14","ecmd":"rcmd"},
"lcmd":{"emit":"d14","ecmd":"lcmd"},
"click":{"emit":"d14","ecmd":"click"},
"dclick":{"emit":"d14","ecmd":"dclick"},
"tclick":{"emit":"d14","ecmd":"tclick"},
"scmd2":{"emit":"d14","ecmd":"scmd2"},
"scmd3":{"emit":"d14","ecmd":"scmd3"},
"lcmd2":{"emit":"d14","ecmd":"lcmd2"},
"lcmd3":{"emit":"d14","ecmd":"lcmd3"},
"rpcmd":{"emit":"d14","ecmd":"rpcmd"},
"rpcmd2":{"emit":"d14","ecmd":"rpcmd2"},
"rpcmd3":{"emit":"d14","ecmd":"rpcmd3"}
},
"69":{"T":2,
"scmd":{"emit":"d15","ecmd":"scmd"},
"rcmd":{"emit":"d15","ecmd":"rcmd"},
"lcmd":{"emit":"d15","ecmd":"lcmd"},
"click":{"emit":"d15","ecmd":"click"},
"dclick":{"emit":"d15","ecmd":"dclick"},
"tclick":{"emit":"d15","ecmd":"tclick"},
"scmd2":{"emit":"d15","ecmd":"scmd2"},
"scmd3":{"emit":"d15","ecmd":"scmd3"},
"lcmd2":{"emit":"d15","ecmd":"lcmd2"},
"lcmd3":{"emit":"d15","ecmd":"lcmd3"},
"rpcmd":{"emit":"d15","ecmd":"rpcmd"},
"rpcmd2":{"emit":"d15","ecmd":"rpcmd2"},
"rpcmd3":{"emit":"d15","ecmd":"rpcmd3"}
}
}
}

View File

@@ -630,6 +630,7 @@ while (remoteConfObj)
strncpy(root+rootLen, addrObj->valuestring, buflen-rootLen-1); strncpy(root+rootLen, addrObj->valuestring, buflen-rootLen-1);
strncat(root+rootLen, "/", buflen-rootLen-1); strncat(root+rootLen, "/", buflen-rootLen-1);
strncat(root+rootLen, "#", buflen-rootLen-1); strncat(root+rootLen, "#", buflen-rootLen-1);
debugSerial.print("CAN: subscribe ");
debugSerial.println(root); debugSerial.println(root);
mqttClient.subscribe(root); mqttClient.subscribe(root);
} }

View File

@@ -272,10 +272,11 @@ for (short rgbwChan=0; rgbwChan < RGBWChannels; rgbwChan++)
} }
} }
//#ifdef _dmxout #ifdef _dmxout
//for (int i=1; i<17; i++) {debugSerial.print(dmxin.read(i));debugSerial.print(";");} debugSerial.print(F("DMXIN:"));
//debugSerial.println(); for (int i=1; i<17; i++) {debugSerial.print(dmxin.read(i));debugSerial.print(";");}
//#endif debugSerial.println();
#endif
#endif #endif
} }
@@ -302,6 +303,7 @@ void DMXinSetup(int channels)
if (channels>(32*4)) channels = 32*4; if (channels>(32*4)) channels = 32*4;
DMXin = new uint8_t [channels]; DMXin = new uint8_t [channels];
DMXINChannels=channels; DMXINChannels=channels;
// debugSerial<<F("DMXIN: init chans:")<<channels<<endl;
#if defined(ARDUINO_ARCH_AVR) #if defined(ARDUINO_ARCH_AVR)
DMXSerial.init(DMXReceiver,0,channels); DMXSerial.init(DMXReceiver,0,channels);
if (DMXSerial.getBuffer()) {debugSerial.print(F("Init in ch:"));debugSerial.println(channels);} else debugSerial.println(F("DMXin Buffer alloc err")); if (DMXSerial.getBuffer()) {debugSerial.print(F("Init in ch:"));debugSerial.println(channels);} else debugSerial.println(F("DMXin Buffer alloc err"));

View File

@@ -683,7 +683,7 @@ debugSerial << F("IN:") << pin << F(" DHT22 type. T=") << temp << F("°C H=") <<
// TODO Polling via timed interrupt with CHECK_INTERRUPT cause // TODO Polling via timed interrupt with CHECK_INTERRUPT cause
bool Input:: bool Input::
changeState(uint8_t newState, short cause, aJsonObject * currentInputObject) changeState(uint8_t newState, short cause, aJsonObject * currentInputObject, bool contactState)
{ {
if (!inputObj || !store) return false; if (!inputObj || !store) return false;
@@ -693,6 +693,7 @@ if (newState == IS_REQSTATE)
// Requested delayed change State and safe moment // Requested delayed change State and safe moment
newState=store->reqState; //Retrieve requested state newState=store->reqState; //Retrieve requested state
debugSerial<<F("Pended: #")<<pin<<F(" ")<<store->state<<F("->") <<newState<<endl; debugSerial<<F("Pended: #")<<pin<<F(" ")<<store->state<<F("->") <<newState<<endl;
contactState = store->lastValue;
if (store->state == newState) if (store->state == newState)
{ {
store->delayedState = false; store->delayedState = false;
@@ -784,6 +785,20 @@ if (newState!=store->state && cause!=CHECK_INTERRUPT) debugSerial<<F("#")<<pin<<
} }
if (cause != CHECK_INTERRUPT)
{
onContactChanged(contactState);
store->delayedState=false;
}
else
{
store->delayedState=true;
store->lastValue = contactState;
store->reqState=newState;
}
if (newState == IS_NOP) return true;
aJsonObject *defaultItem = aJson.getObjectItem(currentInputObject, "item"); aJsonObject *defaultItem = aJson.getObjectItem(currentInputObject, "item");
aJsonObject *defaultEmit = aJson.getObjectItem(currentInputObject, "emit"); aJsonObject *defaultEmit = aJson.getObjectItem(currentInputObject, "emit");
aJsonObject *defaultCan = aJson.getObjectItem(currentInputObject, "can"); aJsonObject *defaultCan = aJson.getObjectItem(currentInputObject, "can");
@@ -835,7 +850,7 @@ void Input::contactPoll(short cause)
contactPollBusy++; contactPollBusy++;
aJsonObject * currentInputObject = getCurrentInput(); aJsonObject * currentInputObject = getCurrentInput();
changeState(IS_REQSTATE,cause,currentInputObject); //Check for postponed states transitions changeState(IS_REQSTATE,cause,currentInputObject,false); //Check for postponed states transitions
uint8_t inputOnLevel; uint8_t inputOnLevel;
@@ -865,15 +880,15 @@ switch (store->state) //Timer based transitions
case IS_PRESSED: case IS_PRESSED:
if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_LONG,0xFFFF)) if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_LONG,0xFFFF))
{ {
if (!aJson.getObjectItem(inputObj, "lcmd") && !aJson.getObjectItem(currentInputObject, "rpcmd")) changeState(IS_WAITRELEASE, cause,currentInputObject); if (!aJson.getObjectItem(inputObj, "lcmd") && !aJson.getObjectItem(currentInputObject, "rpcmd")) changeState(IS_WAITRELEASE, cause,currentInputObject,currentInputState);
else changeState(IS_LONG, cause,currentInputObject); else changeState(IS_LONG, cause,currentInputObject,currentInputState);
} }
break; break;
case IS_LONG: case IS_LONG:
if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_RPT,0xFFFF)) if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_RPT,0xFFFF))
{ {
changeState(IS_REPEAT, cause,currentInputObject); changeState(IS_REPEAT, cause,currentInputObject,currentInputState);
store->timestamp16 = millis() & 0xFFFF; store->timestamp16 = millis() & 0xFFFF;
} }
break; break;
@@ -881,7 +896,7 @@ switch (store->state) //Timer based transitions
case IS_REPEAT: case IS_REPEAT:
if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_RPT_PULSE,0xFFFF)) if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_RPT_PULSE,0xFFFF))
{ {
changeState(IS_REPEAT, cause,currentInputObject); changeState(IS_REPEAT, cause,currentInputObject,currentInputState);
store->timestamp16 = millis() & 0xFFFF; store->timestamp16 = millis() & 0xFFFF;
} }
break; break;
@@ -889,15 +904,15 @@ switch (store->state) //Timer based transitions
case IS_PRESSED2: case IS_PRESSED2:
if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_LONG,0xFFFF)) if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_LONG,0xFFFF))
{ {
if (!aJson.getObjectItem(currentInputObject, "lcmd2") && !aJson.getObjectItem(currentInputObject, "rpcmd2")) changeState(IS_WAITRELEASE, cause,currentInputObject); if (!aJson.getObjectItem(currentInputObject, "lcmd2") && !aJson.getObjectItem(currentInputObject, "rpcmd2")) changeState(IS_WAITRELEASE, cause,currentInputObject,currentInputState);
else changeState(IS_LONG2, cause,currentInputObject); else changeState(IS_LONG2, cause,currentInputObject,currentInputState);
} }
break; break;
case IS_LONG2: case IS_LONG2:
if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_RPT,0xFFFF)) if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_RPT,0xFFFF))
{ {
changeState(IS_REPEAT2, cause,currentInputObject); changeState(IS_REPEAT2, cause,currentInputObject,currentInputState);
store->timestamp16 = millis() & 0xFFFF; store->timestamp16 = millis() & 0xFFFF;
} }
break; break;
@@ -905,7 +920,7 @@ switch (store->state) //Timer based transitions
case IS_REPEAT2: case IS_REPEAT2:
if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_RPT_PULSE,0xFFFF)) if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_RPT_PULSE,0xFFFF))
{ {
changeState(IS_REPEAT2, cause,currentInputObject); changeState(IS_REPEAT2, cause,currentInputObject,currentInputState);
store->timestamp16 = millis() & 0xFFFF; store->timestamp16 = millis() & 0xFFFF;
} }
break; break;
@@ -915,17 +930,17 @@ switch (store->state) //Timer based transitions
{ {
if (!aJson.getObjectItem(currentInputObject, "lcmd3") && !aJson.getObjectItem(currentInputObject, "rpcmd3")) //No longpress handlers if (!aJson.getObjectItem(currentInputObject, "lcmd3") && !aJson.getObjectItem(currentInputObject, "rpcmd3")) //No longpress handlers
{ {
if (aJson.getObjectItem(currentInputObject, "scmd3")) changeState(IS_WAITRELEASE, cause,currentInputObject); //was used if (aJson.getObjectItem(currentInputObject, "scmd3")) changeState(IS_WAITRELEASE, cause,currentInputObject,currentInputState); //was used
else changeState(IS_PRESSED2, cause,currentInputObject); // completely empty trippleClick section - fallback to first click handler else changeState(IS_PRESSED2, cause,currentInputObject,currentInputState); // completely empty trippleClick section - fallback to first click handler
} }
else changeState(IS_LONG3, cause,currentInputObject); else changeState(IS_LONG3, cause,currentInputObject,currentInputState);
} }
break; break;
case IS_LONG3: case IS_LONG3:
if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_RPT,0xFFFF)) if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_RPT,0xFFFF))
{ {
changeState(IS_REPEAT3, cause,currentInputObject); changeState(IS_REPEAT3, cause,currentInputObject,currentInputState);
store->timestamp16 = millis() & 0xFFFF; store->timestamp16 = millis() & 0xFFFF;
} }
break; break;
@@ -933,7 +948,7 @@ switch (store->state) //Timer based transitions
case IS_REPEAT3: case IS_REPEAT3:
if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_RPT_PULSE,0xFFFF)) if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_RPT_PULSE,0xFFFF))
{ {
changeState(IS_REPEAT3, cause,currentInputObject); changeState(IS_REPEAT3, cause,currentInputObject,currentInputState);
store->timestamp16 = millis() & 0xFFFF; store->timestamp16 = millis() & 0xFFFF;
} }
break; break;
@@ -943,7 +958,7 @@ switch (store->state) //Timer based transitions
case IS_WAITPRESS: case IS_WAITPRESS:
if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_IDLE,0xFFFF)) changeState(IS_IDLE, cause,currentInputObject); if (isTimeOver(store->timestamp16,millis() & 0xFFFF,T_IDLE,0xFFFF)) changeState(IS_IDLE, cause,currentInputObject,currentInputState);
break; break;
} //switch } //switch
#ifdef ROTARYENCODER #ifdef ROTARYENCODER
@@ -963,7 +978,8 @@ if (re)
} }
#endif #endif
} //if not INTERRUPT } //if not INTERRUPT
if (currentInputState != store->lastValue) // value changed if ((currentInputState != store->lastValue) || // value changed
(isTimeOver(store->timestamp16,millis() & 0xFFFF,T_REPEAT,0xFFFF) && getIntFromJson(currentInputObject,"repeat")))
{ {
if (store->bounce) store->bounce = store->bounce - 1; if (store->bounce) store->bounce = store->bounce - 1;
else //confirmed change else //confirmed change
@@ -981,7 +997,7 @@ if (re)
} else */ } else */
{ {
// onContactChanged(currentInputState); //Legacy input - to remove later ////// onContactChanged(currentInputState); //Legacy input - to remove later // wrong place - INTERRUPTS
bool res = true; bool res = true;
if (currentInputState) //Button pressed state transitions if (currentInputState) //Button pressed state transitions
@@ -989,7 +1005,7 @@ if (re)
switch (store->state) switch (store->state)
{ {
case IS_IDLE: case IS_IDLE:
res = changeState(IS_PRESSED, cause,currentInputObject); res = changeState(IS_PRESSED, cause,currentInputObject,currentInputState);
break; break;
@@ -1001,30 +1017,33 @@ if (re)
!aJson.getObjectItem(currentInputObject, "rpcmd2") && !aJson.getObjectItem(currentInputObject, "rpcmd2") &&
!aJson.getObjectItem(currentInputObject, "dclick") !aJson.getObjectItem(currentInputObject, "dclick")
) )
res = changeState(IS_PRESSED, cause,currentInputObject); res = changeState(IS_PRESSED, cause,currentInputObject,currentInputState);
else res = changeState(IS_PRESSED2, cause,currentInputObject); else res = changeState(IS_PRESSED2, cause,currentInputObject,currentInputState);
break; break;
case IS_RELEASED2: case IS_RELEASED2:
res = changeState(IS_PRESSED3, cause,currentInputObject); res = changeState(IS_PRESSED3, cause,currentInputObject,currentInputState);
break; break;
default:
res = changeState(IS_NOP, cause,currentInputObject,currentInputState);
} }
else else
switch (store->state) //Button released state transitions switch (store->state) //Button released state transitions
{ {
case IS_PRESSED: case IS_PRESSED:
res = changeState(IS_RELEASED, cause,currentInputObject); res = changeState(IS_RELEASED, cause,currentInputObject,currentInputState);
break; break;
case IS_LONG: case IS_LONG:
case IS_REPEAT: case IS_REPEAT:
case IS_WAITRELEASE: case IS_WAITRELEASE:
res = changeState(IS_WAITPRESS, cause,currentInputObject); res = changeState(IS_WAITPRESS, cause,currentInputObject,currentInputState);
break; break;
case IS_PRESSED2: case IS_PRESSED2:
@@ -1033,8 +1052,8 @@ if (re)
!aJson.getObjectItem(currentInputObject, "lcmd2") && !aJson.getObjectItem(currentInputObject, "lcmd2") &&
!aJson.getObjectItem(currentInputObject, "rpcmd2") && !aJson.getObjectItem(currentInputObject, "rpcmd2") &&
!aJson.getObjectItem(currentInputObject, "dclick") !aJson.getObjectItem(currentInputObject, "dclick")
) res = changeState(IS_IDLE, cause,currentInputObject); ) res = changeState(IS_IDLE, cause,currentInputObject,currentInputState);
else res = changeState(IS_RELEASED2, cause,currentInputObject); else res = changeState(IS_RELEASED2, cause,currentInputObject,currentInputState);
break; break;
case IS_LONG2: case IS_LONG2:
@@ -1042,8 +1061,10 @@ if (re)
case IS_LONG3: case IS_LONG3:
case IS_REPEAT3: case IS_REPEAT3:
case IS_PRESSED3: case IS_PRESSED3:
res = changeState(IS_IDLE, cause,currentInputObject); res = changeState(IS_IDLE, cause,currentInputObject,currentInputState);
break; break;
default:
res = changeState(IS_NOP, cause,currentInputObject,currentInputState);
} }
if (res) { //State changed or postponed if (res) { //State changed or postponed
// store->logicState = currentInputState; // store->logicState = currentInputState;

View File

@@ -56,6 +56,7 @@ e-mail anklimov@gmail.com
#define IS_REPEAT3 12u #define IS_REPEAT3 12u
#define IS_WAITRELEASE 13u #define IS_WAITRELEASE 13u
#define IS_REQSTATE 0xFF #define IS_REQSTATE 0xFF
#define IS_NOP 0xF
@@ -73,6 +74,7 @@ e-mail anklimov@gmail.com
#define T_IDLE 600 #define T_IDLE 600
#define T_RPT 300 #define T_RPT 300
#define T_RPT_PULSE 150 #define T_RPT_PULSE 150
#define T_REPEAT 30000
@@ -191,7 +193,7 @@ protected:
bool publishDataToDomoticz(int , aJsonObject *, const char *format, ...); bool publishDataToDomoticz(int , aJsonObject *, const char *format, ...);
char* getIdxField(); char* getIdxField();
bool changeState(uint8_t newState, short cause, aJsonObject * currentInputObject); bool changeState(uint8_t newState, short cause, aJsonObject * currentInputObject, bool contactState);
void setupRotaryEncoder(); void setupRotaryEncoder();
aJsonObject * getCurrentInput(); aJsonObject * getCurrentInput();

View File

@@ -358,7 +358,7 @@ uint16_t getCanNum(aJsonObject* verb)
char * Item::getSubItemStrById(uint8_t subItem) char * Item::getSubItemStrById(uint8_t subItem)
{ {
if (subItem == NO_SUBITEM || (subItem | SUBITEM_IS_COMMAND)) return NULL; if (subItem == NO_SUBITEM || (subItem & SUBITEM_IS_COMMAND)) return NULL;
if (!itemArg) return NULL; if (!itemArg) return NULL;
aJsonObject * i = itemArg; aJsonObject * i = itemArg;
if (i->type == aJson_Array) i=i->child; if (i->type == aJson_Array) i=i->child;
@@ -421,18 +421,20 @@ return NO_SUBITEM;
{ {
if (getCanNum(itemArr->child) == num) if (getCanNum(itemArr->child) == num)
{ {
debugSerial<<"Find item: "<< itemArr->name << " addr:" << num << endl; debugSerial<<"CAN: Find item: "<< itemArr->name << " id:" << num << "sub:" << subItem;
Parse(); Parse();
if (subItem | SUBITEM_IS_COMMAND) if (subItem & SUBITEM_IS_COMMAND)
{ {
subItem &=~ SUBITEM_IS_COMMAND; subItem &=~ SUBITEM_IS_COMMAND;
if (subItem<commandsNum) strncpy_P(defaultSubItem, commands_P[subItem], sizeof(defaultSubItem)); if (subItem<commandsNum) strncpy_P(defaultSubItem, commands_P[subItem], sizeof(defaultSubItem));
debugSerial<<" subcmd:"<<defaultSubItem<<endl;
} }
else else
{ {
char * subItemStr = getSubItemStrById(subItem); char * subItemStr = getSubItemStrById(subItem);
if (subItemStr) strncpy(defaultSubItem,subItemStr,sizeof(defaultSubItem)); if (subItemStr) strncpy(defaultSubItem,subItemStr,sizeof(defaultSubItem));
} debugSerial<<" subname:"<<defaultSubItem<<endl;
}
return; return;
} }
itemArr = itemArr->next; itemArr = itemArr->next;
@@ -1107,7 +1109,7 @@ int Item::Ctrl(itemCmd cmd, char* subItem, uint8_t flags, bool authorized)
uint8_t command2Set = 0; uint8_t command2Set = 0;
itemCmd originalCmd = cmd; itemCmd originalCmd = cmd;
int subitemCmd = subitem2cmd(subItem); int subitemCmd = subitem2cmd(subItem);
bool oppositeCommandToBeSchedulled = (suffixCode==S_CMD) && cmd.isValue();
/// Common (GRP & NO GRP) commands /// Common (GRP & NO GRP) commands
switch (cmd.getCmd()) switch (cmd.getCmd())
{ {
@@ -1293,14 +1295,14 @@ int Item::Ctrl(itemCmd cmd, char* subItem, uint8_t flags, bool authorized)
} }
else else
{ {
//chActive=(isActive()>0); if (chActive == -1) chActive=(isActive()>0); //need! because activities status will be changed
if ((suffixCode!=S_CMD) || (cmd.getCmd() != CMD_XON) || !getFlag(FLAG_DISABLED)) if ((suffixCode!=S_CMD) || (cmd.getCmd() != CMD_XON) || !getFlag(FLAG_DISABLED))
{ {
digGroup(itemArg,&cmd,subItem,authorized,flags); digGroup(itemArg,&cmd,subItem,authorized,flags);
if ((suffixCode==S_CMD) && cmd.isValue()) if (oppositeCommandToBeSchedulled)//((suffixCode==S_CMD) && cmd.isValue())
{ {
scheduleOppositeCommand(originalCmd,-1/*chActive*/,authorized); scheduleOppositeCommand(originalCmd,-1,authorized);
scheduledOppositeCommand = true; scheduledOppositeCommand = true;
} }
if (subItem && !subitemCmd) status2Send |= FLAG_SEND_IMMEDIATE; if (subItem && !subitemCmd) status2Send |= FLAG_SEND_IMMEDIATE;
@@ -1347,8 +1349,6 @@ int Item::Ctrl(itemCmd cmd, char* subItem, uint8_t flags, bool authorized)
if (chActive == -1) chActive=(isActive()>0); if (chActive == -1) chActive=(isActive()>0);
if (!chActive) //if channel was'nt active before CMD_XON if (!chActive) //if channel was'nt active before CMD_XON
{ {
cmd.loadItemDef(this); cmd.loadItemDef(this);
cmd.Cmd(CMD_ON); cmd.Cmd(CMD_ON);
command2Set=CMD_XON; command2Set=CMD_XON;
@@ -1424,7 +1424,7 @@ int Item::Ctrl(itemCmd cmd, char* subItem, uint8_t flags, bool authorized)
/// bool oppositeCommandToBeSchedulled = (suffixCode==S_CMD) && allowRecursion && cmd.isValue(); /// bool oppositeCommandToBeSchedulled = (suffixCode==S_CMD) && allowRecursion && cmd.isValue();
bool oppositeCommandToBeSchedulled = (suffixCode==S_CMD) && cmd.isValue(); // bool oppositeCommandToBeSchedulled = (suffixCode==S_CMD) && cmd.isValue();
// Commands for NON GROUP // Commands for NON GROUP
//threating Restore, XOFF (special conditional commands)/ convert to ON, OFF and SET values //threating Restore, XOFF (special conditional commands)/ convert to ON, OFF and SET values
switch (cmd.getCmd()) { switch (cmd.getCmd()) {
@@ -1740,7 +1740,14 @@ if ((!driver || driver->isAllowed(cmd))
//update command for HALT & XON and send MQTT status //update command for HALT & XON and send MQTT status
if (command2Set) setCmd(command2Set | FLAG_COMMAND); if (command2Set) setCmd(command2Set | FLAG_COMMAND);
if (operation) SendStatus(status2Send,subItem); if (operation) {
SendStatus(status2Send);//,subItem);
if (oppositeCommandToBeSchedulled && subItem)
{
debugSerial<<F("CTRL: momentary event")<<endl;
SendStatusImmediate(originalCmd,status2Send,subItem,false); //XON -> OFF scheduled
}
}
} //alowed cmd } //alowed cmd
else else
{ {
@@ -1934,11 +1941,11 @@ int Item::SendStatus(long sendFlags, char * subItem) {
} }
} }
int Item::SendStatusImmediate(itemCmd st, long sendFlags, char * subItem) { int Item::SendStatusImmediate(itemCmd st, long sendFlags, char * subItem, bool retain) {
{ {
char addrstr[64]; char addrstr[64];
char valstr[20] = ""; char valstr[20] = "";
char cmdstr[9] = ""; char cmdstr[16] = "";
debugSerial<<"SENDSTATUS: "<<subItem<<" "; debugSerial<<"SENDSTATUS: "<<subItem<<" ";
st.debugOut(); st.debugOut();
@@ -1997,12 +2004,12 @@ int Item::SendStatus(long sendFlags, char * subItem) {
(st.getArgType() == ST_PERCENTS255 || st.getArgType() == ST_HSV255 || st.getArgType() == ST_FLOAT_CELSIUS)) (st.getArgType() == ST_PERCENTS255 || st.getArgType() == ST_HSV255 || st.getArgType() == ST_FLOAT_CELSIUS))
{ {
st.toString(valstr, sizeof(valstr), FLAG_PARAMETERS,true); st.toString(valstr, sizeof(valstr), FLAG_PARAMETERS,true);
mqttClient.publish(addrstr, valstr, true); mqttClient.publish(addrstr, valstr, retain);
debugSerial<<F("Pub: ")<<addrstr<<F("->")<<valstr<<endl; debugSerial<<F("Pub: ")<<addrstr<<F("->")<<valstr<<endl;
} }
else if ((sendFlags & FLAG_COMMAND) && (strlen(cmdstr))) else if ((sendFlags & FLAG_COMMAND) && (strlen(cmdstr)))
{ {
mqttClient.publish(addrstr, cmdstr, true); mqttClient.publish(addrstr, cmdstr, retain);
debugSerial<<F("Pub: ")<<addrstr<<F("->")<<cmdstr<<endl; debugSerial<<F("Pub: ")<<addrstr<<F("->")<<cmdstr<<endl;
} }
@@ -2068,7 +2075,7 @@ int Item::SendStatus(long sendFlags, char * subItem) {
#if not defined (NOIP) #if not defined (NOIP)
if (mqttClient.connected() && !ethernetIdleCount) if (mqttClient.connected() && !ethernetIdleCount)
{ {
mqttClient.publish(addrstr, valstr,true); mqttClient.publish(addrstr, valstr,retain);
clearFlag(FLAG_PARAMETERS); clearFlag(FLAG_PARAMETERS);
} }
else else
@@ -2082,6 +2089,7 @@ int Item::SendStatus(long sendFlags, char * subItem) {
if (sendFlags & FLAG_COMMAND) if (sendFlags & FLAG_COMMAND)
{ {
if (!subItem)
// Some additional preparing for extended set of commands: // Some additional preparing for extended set of commands:
switch (st.getCmd()) { switch (st.getCmd()) {
case CMD_AUTO: case CMD_AUTO:
@@ -2112,6 +2120,8 @@ int Item::SendStatus(long sendFlags, char * subItem) {
case CMD_XON: case CMD_XON:
if (itemType == CH_THERMO) strcpy_P(cmdstr, AUTO_P); if (itemType == CH_THERMO) strcpy_P(cmdstr, AUTO_P);
} }
else //for subItems - transpatent print
st.toString(cmdstr,sizeof(cmdstr),FLAG_COMMAND | FLAG_PARAMETERS);
setTopic(addrstr,sizeof(addrstr),T_OUT); setTopic(addrstr,sizeof(addrstr),T_OUT);
strncat(addrstr, itemArr->name, sizeof(addrstr)-1); strncat(addrstr, itemArr->name, sizeof(addrstr)-1);
@@ -2128,7 +2138,7 @@ int Item::SendStatus(long sendFlags, char * subItem) {
#if not defined (NOIP) #if not defined (NOIP)
if (mqttClient.connected() && !ethernetIdleCount) if (mqttClient.connected() && !ethernetIdleCount)
{ {
mqttClient.publish(addrstr, cmdstr,true); mqttClient.publish(addrstr, cmdstr,retain);
clearFlag(FLAG_COMMAND); clearFlag(FLAG_COMMAND);
} }
else else
@@ -2168,7 +2178,7 @@ int Item::SendStatus(long sendFlags, char * subItem) {
#if not defined (NOIP) #if not defined (NOIP)
if (mqttClient.connected() && !ethernetIdleCount) if (mqttClient.connected() && !ethernetIdleCount)
{ {
mqttClient.publish(addrstr, cmdstr,true); mqttClient.publish(addrstr, cmdstr,retain);
clearFlag(FLAG_FLAGS); clearFlag(FLAG_FLAGS);
} }
else else

View File

@@ -145,7 +145,7 @@ class Item
void setSubtype(uint8_t par); void setSubtype(uint8_t par);
int Poll(int cause); int Poll(int cause);
int SendStatus(long sendFlags, char * subItem=NULL); int SendStatus(long sendFlags, char * subItem=NULL);
int SendStatusImmediate(itemCmd st, long sendFlags, char * subItem=NULL); int SendStatusImmediate(itemCmd st, long sendFlags, char * subItem=NULL, bool tetain = true);
int isActive(); int isActive();
int getChanType(); int getChanType();
inline int On (){return Ctrl(itemCmd(ST_VOID,CMD_ON));}; inline int On (){return Ctrl(itemCmd(ST_VOID,CMD_ON));};

View File

@@ -289,7 +289,7 @@ if (Status() == AC_SENDING)
ACSerial->write(getCRC(req, size-1)); ACSerial->write(getCRC(req, size-1));
//ACSerial->flush(); //ACSerial->flush();
store->timestamp=millisNZ(); store->timestamp=millisNZ();
debugSerial<<F("AC: ")<<portNum<<F(" <<"); debugSerial<<F("AC:")<<portNum<<F(" << ");
for (int i=0; i < size-1; i++) for (int i=0; i < size-1; i++)
{ {
if (req[i] < 10){ if (req[i] < 10){
@@ -436,35 +436,37 @@ case AC_AWAITINGCMD: //Flusing port for 5 sec, poll status
SendData(qstn, sizeof(qstn)/sizeof(byte)); //Опрос кондиционера SendData(qstn, sizeof(qstn)/sizeof(byte)); //Опрос кондиционера
} }
*/ */
byte tmpdata[sizeof(store->data)];
if(ACSerial->available() >= 37){ //was 0 if(ACSerial->available() >= 37){ //was 0
ACSerial->readBytes(store->data, 37); ACSerial->readBytes(tmpdata, 37);
while(ACSerial->available()){ while(ACSerial->available()){
delay(2); delay(2);
ACSerial->read(); ACSerial->read();
} }
debugSerial<<F("AC: ")<<portNum<<F(" >> "); debugSerial<<F("AC:")<<portNum<<F(" >> ");
for (int i=0; i < 37-1; i++) for (int i=0; i < 37-1; i++)
{ {
if (store->data[i] < 10){ if (tmpdata[i] < 10){
debugSerial.print("0"); debugSerial.print("0");
debugSerial.print(store->data[i], HEX); debugSerial.print(tmpdata[i], HEX);
} }
else else
{ {
debugSerial.print(store->data[i], HEX); debugSerial.print(tmpdata[i], HEX);
} }
} }
debugSerial.println('.'); debugSerial.println('.');
uint8_t crc=getCRC(store->data,36); uint8_t crc=getCRC(tmpdata,36);
if (store->data[36] == crc) if (tmpdata[36] == crc)
{ {
debugSerial<<F("AC: OK")<<endl; debugSerial<<F("AC: OK")<<endl;
if (store->data[36] != store->inCheck) if (tmpdata[36] != store->inCheck)
{ //Updated { //Updated
store->inCheck = store->data[36]; store->inCheck = tmpdata[36];
memcpy(store->data,tmpdata,sizeof(store->data));
InsertData(store->data, 37); InsertData(store->data, 37);
} }
} }

View File

@@ -126,8 +126,9 @@ int out_Multivent::Poll(short cause)
if (gatesObj) if (gatesObj)
{ {
// metrics, collected from AC // metrics, collected from AC
float acTemp = getFloatFromJson(aJson.getObjectItem(gatesObj, ""),"val",NAN); aJsonObject * a = aJson.getObjectItem(gatesObj, "");
int actualCmd = item->getCmd(); float acTemp = getFloatFromJson(a,"val",NAN);
int actualCmd = getIntFromJson (a,"mode");
int actualMode = CMD_FAN; int actualMode = CMD_FAN;
if (acTemp>30.0) actualMode = CMD_HEAT; if (acTemp>30.0) actualMode = CMD_HEAT;
else if (acTemp<15.0) actualMode = CMD_COOL; else if (acTemp<15.0) actualMode = CMD_COOL;
@@ -189,12 +190,12 @@ int out_Multivent::Poll(short cause)
case CMD_HEAT: case CMD_HEAT:
((PID *) pidObj->valueint)->SetControllerDirection(DIRECT); ((PID *) pidObj->valueint)->SetControllerDirection(DIRECT);
debugSerial<<F("VENT: PASS PID: ")<<item->itemArr->name<<"/"<<i->name<<F(" set DIRECT mode")<<endl; debugSerial<<F("VENT: PASS PID: ")<<item->itemArr->name<<"/"<<i->name<<F(" set DIRECT mode")<<endl;
Ctrl(itemCmd().Percents255(poObj->valuefloat).setSuffix(S_FAN),i->name); if (actualCmd!=CMD_OFF) Ctrl(itemCmd().Percents255(poObj->valuefloat).setSuffix(S_FAN),i->name);
break; break;
case CMD_COOL: case CMD_COOL:
((PID *) pidObj->valueint)->SetControllerDirection(REVERSE); ((PID *) pidObj->valueint)->SetControllerDirection(REVERSE);
debugSerial<<F("VENT: PASS PID: ")<<item->itemArr->name<<"/"<<i->name<<F(" set REVERSE mode")<<endl; debugSerial<<F("VENT: PASS PID: ")<<item->itemArr->name<<"/"<<i->name<<F(" set REVERSE mode")<<endl;
Ctrl(itemCmd().Percents255(poObj->valuefloat).setSuffix(S_FAN),i->name); if (actualCmd!=CMD_OFF) Ctrl(itemCmd().Percents255(poObj->valuefloat).setSuffix(S_FAN),i->name);
} }
break; break;
case CMD_HEAT: case CMD_HEAT:
@@ -239,7 +240,8 @@ int out_Multivent::sendACcmd (int cmd)
aJsonObject * a = aJson.getObjectItem(gatesObj, ""); aJsonObject * a = aJson.getObjectItem(gatesObj, "");
if (!a) return 0; if (!a) return 0;
int lastCmd = getIntFromJson(a,"@lastCmd"); int lastCmd = getIntFromJson(a,"@lastCmd");
if (lastCmd && (item->getCmd() != lastCmd)) { int acCmd = getIntFromJson(a,"mode");
if (lastCmd && (acCmd != lastCmd)) {
//debugSerial<<"VENT: AC MODE changed manually to "<<item->getCmd()<<endl; //debugSerial<<"VENT: AC MODE changed manually to "<<item->getCmd()<<endl;
return 0;} return 0;}
if (cmd == lastCmd) { if (cmd == lastCmd) {
@@ -252,7 +254,7 @@ int out_Multivent::sendACcmd (int cmd)
int out_Multivent::getChanType() int out_Multivent::getChanType()
{ {
return CH_PWM; return CH_THERMO; /////PWM
} }
@@ -274,18 +276,6 @@ switch (suffixCode)
debugSerial << F("VENT:")<<F("AC air temp: ")<< cmd.getFloat()<<endl; debugSerial << F("VENT:")<<F("AC air temp: ")<< cmd.getFloat()<<endl;
item->setExt(millisNZ()); item->setExt(millisNZ());
setValToJson(aJson.getObjectItem(gatesObj, ""),"val",cmd.getFloat()); setValToJson(aJson.getObjectItem(gatesObj, ""),"val",cmd.getFloat());
/*
int mode = CMD_FAN;
int temp = cmd.getInt();
if (temp>30) mode = CMD_HEAT;
else if (temp<17) mode = CMD_COOL;
if (item->getCmd() != mode)
{
item->setCmd(mode);
pubAction(item->isActive());
}
*/
} }
return 1; return 1;
@@ -296,6 +286,10 @@ switch (suffixCode)
return 1; return 1;
case S_MODE: case S_MODE:
debugSerial << F("VENT:")<<F("AC mode: ")<< cmd.getCmd()<<endl;
setValToJson(aJson.getObjectItem(gatesObj, ""),"mode",cmd.getCmd());
return 1;
case S_CMD: case S_CMD:
return 1; return 1;

View File

@@ -9,7 +9,7 @@
#endif #endif
#ifndef LOGBUFFER_SIZE #ifndef LOGBUFFER_SIZE
#define LOGBUFFER_SIZE 80 #define LOGBUFFER_SIZE 85
#endif #endif
#ifdef SYSLOG_ENABLE #ifdef SYSLOG_ENABLE

View File

@@ -663,7 +663,7 @@ bool executeCommand(aJsonObject* cmd, int8_t toggle)
bool executeCommand(aJsonObject* cmd, int8_t toggle, itemCmd _itemCmd, aJsonObject* defaultItem, aJsonObject* defaultEmit, aJsonObject* defaultCan) bool executeCommand(aJsonObject* cmd, int8_t toggle, itemCmd _itemCmd, aJsonObject* defaultItem, aJsonObject* defaultEmit, aJsonObject* defaultCan)
//bool executeCommand(aJsonObject* cmd, int8_t toggle, char* defCmd) //bool executeCommand(aJsonObject* cmd, int8_t toggle, char* defCmd)
{ {
//char * legacyString =NULL; if (!cmd) return false;
aJsonObject *item = NULL; aJsonObject *item = NULL;
aJsonObject *emit = NULL; aJsonObject *emit = NULL;
aJsonObject *can = NULL; aJsonObject *can = NULL;
@@ -679,7 +679,7 @@ debugSerial<<"Exec:"<<out<<endl;
free (out); free (out);
} }
} }
if (cmd) cmdType = cmd->type; cmdType = cmd->type;
switch (cmdType) switch (cmdType)
{ {
@@ -1043,6 +1043,7 @@ if (a->type == aJson_Array)
// TODO - human readable JSON objects as alias // TODO - human readable JSON objects as alias
if (element && element->type == aJson_Int) return element->valueint; if (element && element->type == aJson_Int) return element->valueint;
if (element && element->type == aJson_Float) return element->valuefloat; if (element && element->type == aJson_Float) return element->valuefloat;
if (element && element->type == aJson_Boolean) return element->valuebool;
return def; return def;
} }
@@ -1055,6 +1056,8 @@ if (a->type == aJson_Object)
element = aJson.getObjectItem(a, name); element = aJson.getObjectItem(a, name);
if (element && element->type == aJson_Int) return element->valueint; if (element && element->type == aJson_Int) return element->valueint;
if (element && element->type == aJson_Float) return element->valuefloat; if (element && element->type == aJson_Float) return element->valuefloat;
if (element && element->type == aJson_Boolean) return element->valuebool;
return def; return def;
} }