Skip to content

Commit

Permalink
Merge remote-tracking branch 'ewowi/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
ewoudwijma committed May 2, 2024
2 parents afeaab8 + 4879437 commit e1f0bf1
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 155 deletions.
2 changes: 1 addition & 1 deletion platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ build_flags =
; ${STARBASE_USERMOD_HA.build_flags}
${STARLEDS_USERMOD_WLEDAUDIO.build_flags}
-DAPP=StarLeds
-DVERSION=24050120 ; Date and time (GMT!)
-DVERSION=24050213 ; Date and time (GMT!)
-DPIOENV=$PIOENV
lib_deps =
${StarBase.lib_deps}
Expand Down
247 changes: 93 additions & 154 deletions src/User/UserModInstances.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,94 +21,29 @@ struct DMX {
byte count:4; // 4 bits / 16
}; //total 16 bits

//additional data not in wled header
struct SysData {
unsigned long upTime;
byte type;
byte syncMaster;
DMX dmx;
uint8_t macAddress[6]; // 48 bits
};

struct VarData {
char id[3];
byte value;
}; //4

#define nrOfAppVars 20

struct AppData {
VarData vars[nrOfAppVars]; //total 80

bool str3cmp(const char * lhs, const char * rhs) {
for (int i = 0; i < 3; i++) {
if (lhs[i] == '\0' || rhs[i] == '\0')
return true;
if (lhs[i] != rhs[i])
return false;
}
return true;
}

void str3cpy(char * lhs, const char * rhs) {
bool found0 = false;
for (int i = 0; i < 3; i++) {
if (rhs[i] == '\0')
found0 = true;
if (!found0)
lhs[i] = rhs[i]; //copy
else
lhs[i] = '\0'; //add 0
}
}

int getVar(const char * varID) { //int to support -1
for (int i=0; i < nrOfAppVars; i++) {
// ppf("getVar %d %s %s %d\n", i, varID, vars[i].id, vars[i].value);
if (varID && !str3cmp(vars[i].id, "-") && str3cmp(vars[i].id, varID)) {
return vars[i].value;
}
}
// ppf("getVar %s not found\n", varID);
return -1;
}

void setVar(const char * varID, unsigned8 value) {
size_t foundAppVar;
for (int i=0; i< nrOfAppVars; i++) {
if (str3cmp(vars[i].id, "-")) {
foundAppVar = i; //use empty slot
break;
}
else if (str3cmp(vars[i].id, varID)) {
foundAppVar = i; //use existing slot for var
break;
}
}
size_t i = foundAppVar;
if (str3cmp(vars[i].id, "-")) str3cpy(vars[i].id, varID); //assign empty slot to var
vars[i].value = value;
// ppf("setVar %d %s %d\n", i, varID, vars[i].value);
}

void initVars() {
for (int i = 0; i < nrOfAppVars; i++) {
str3cpy(vars[i].id, "-");
vars[i].value = 0;
}
}

};

//note: changing SysData and AppData sizes: all instances should have the same version so change with care
//note: changing SysData and jsonData sizes: all instances should have the same version so change with care

struct InstanceInfo {
IPAddress ip;
char name[32];
uint8_t macAddress[6]; // 48 bits
uint32_t version;
unsigned long timeStamp; //when was the package received, used to check on aging
SysData sys;
AppData app; //total 80

SysData sysData;
JsonDocument jsonData;
};

struct UDPWLEDMessage {
Expand All @@ -127,9 +62,8 @@ struct UDPWLEDMessage {
//compatible with WLED instances as it only interprets first 44 bytes
struct UDPStarMessage {
UDPWLEDMessage header; // 44 bytes fixed!
SysData sys;
AppData app;
char body[1460 - sizeof(UDPWLEDMessage) - sizeof(SysData) - sizeof(AppData)];
SysData sysData;
char jsonString[1460 - sizeof(UDPWLEDMessage) - sizeof(SysData)];
};

//WLED syncmessage
Expand Down Expand Up @@ -222,7 +156,7 @@ class UserModInstances:public SysModule {
ui->initText(tableVar, "insType", nullptr, 16, true, [this](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun
case f_ValueFun:
for (forUnsigned8 rowNrL = 0; rowNrL < instances.size() && (rowNr == UINT8_MAX || rowNrL == rowNr); rowNrL++)
mdl->setValue(var, (instances[rowNrL].sys.type==0)?"WLED":(instances[rowNrL].sys.type==1)?"StarBase":(instances[rowNrL].sys.type==2)?"StarLeds":"StarFork", rowNrL);
mdl->setValue(var, (instances[rowNrL].sysData.type==0)?"WLED":(instances[rowNrL].sysData.type==1)?"StarBase":(instances[rowNrL].sysData.type==2)?"StarLeds":"StarFork", rowNrL);
return true;
case f_UIFun:
ui->setLabel(var, "Type");
Expand All @@ -244,7 +178,7 @@ class UserModInstances:public SysModule {
ui->initNumber(tableVar, "insUp", UINT16_MAX, 0, (unsigned long)-1, true, [this](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun
case f_ValueFun:
for (forUnsigned8 rowNrL = 0; rowNrL < instances.size() && (rowNr == UINT8_MAX || rowNrL == rowNr); rowNrL++)
mdl->setValue(var, instances[rowNrL].sys.upTime, rowNrL);
mdl->setValue(var, instances[rowNrL].sysData.upTime, rowNrL);
return true;
case f_UIFun:
ui->setLabel(var, "Uptime");
Expand Down Expand Up @@ -293,10 +227,11 @@ class UserModInstances:public SysModule {
for (forUnsigned8 rowNrL = 0; rowNrL < instances.size() && (rowNr == UINT8_MAX || rowNrL == rowNr); rowNrL++) {
// ppf("initVar dash %s[%d]\n", mdl->varID(insVar), rowNrL);
//do what setValue is doing except calling changeFun
// insVar["value"][rowNrL] = instances[rowNrL].app.getVar(mdl->varID(var)); //only int values...
web->addResponse(insVar["id"], "value", instances[rowNrL].app.getVar(mdl->varID(var)), rowNrL); //only int values...);
// insVar["value"][rowNrL] = instances[rowNrL].jsonData[mdl->varID(var)]; //only int values...

// mdl->setValue(insVar, instances[rowNr].app.getVar(var["id"]), rowNr);
web->addResponse(insVar["id"], "value", instances[rowNrL].jsonData[mdl->varID(var)], rowNrL);

// mdl->setValue(insVar, instances[rowNrL].jsonData[mdl->varID(var)], rowNr);
//send to ws?
}
return true;
Expand Down Expand Up @@ -327,7 +262,7 @@ class UserModInstances:public SysModule {
web->sendUDPCounter++;
web->sendUDPBytes+=sizeof(buffer);
instanceUDP.endPacket();
ppf("StarMod udp json write %s\n", buffer);
ppf("udp json write %s\n", buffer);
}
}
}
Expand Down Expand Up @@ -421,18 +356,18 @@ class UserModInstances:public SysModule {

InstanceInfo *instance = findInstance(remoteIp); //if not exist, created

instance->sys.upTime = (wledSyncMessage.timebase[0] * 256*256*256 + 256*256*wledSyncMessage.timebase[1] + 256*wledSyncMessage.timebase[2] + wledSyncMessage.timebase[3]) / 1000;
instance->sys.syncMaster = wledSyncMessage.syncGroups; //tbd: change
instance->sysData.upTime = (wledSyncMessage.timebase[0] * 256*256*256 + 256*256*wledSyncMessage.timebase[1] + 256*wledSyncMessage.timebase[2] + wledSyncMessage.timebase[3]) / 1000;
instance->sysData.syncMaster = wledSyncMessage.syncGroups; //tbd: change

stackUnsigned8 syncMaster = mdl->getValue("sma");
if (syncMaster == remoteIp[3]) {
if (instance->app.getVar("bri") != wledSyncMessage.bri) mdl->setValue("bri", wledSyncMessage.bri);
if (instance->jsonData["bri"] != wledSyncMessage.bri) mdl->setValue("bri", wledSyncMessage.bri);
//only set brightness
}

instance->app.setVar("bri", wledSyncMessage.bri);
instance->app.setVar("fx", wledSyncMessage.mainsegMode); //tbd: rowNr
instance->app.setVar("pal", wledSyncMessage.palette); //tbd: rowNr
instance->jsonData["bri"] = wledSyncMessage.bri;
instance->jsonData["fx"] = wledSyncMessage.mainsegMode; //tbd: rowNr
instance->jsonData["pal"] = wledSyncMessage.palette; //tbd: rowNr

// for (size_t x = 0; x < packetSize; x++) {
// char xx = (char)udpIn[x];
Expand Down Expand Up @@ -464,19 +399,19 @@ class UserModInstances:public SysModule {
byte *udpIn = (byte *)&starMessage.header;
instanceUDP.read(udpIn, packetSize);

starMessage.sys.type = 0; //WLED
starMessage.sysData.type = 0; //WLED

updateInstance(starMessage);
}
else if (packetSize == sizeof(UDPStarMessage)) { //StarBase instance
UDPStarMessage starMessage;
byte *udpIn = (byte *)&starMessage;
instanceUDP.read(udpIn, packetSize);
starMessage.sys.type = (strcmp(_INIT(TOSTRING(APP)), "StarBase")==0)?1:(strcmp(_INIT(TOSTRING(APP)), "StarLeds")==0)?2:3; //1=StarBase,2=StarLeds, 3=StarFork
starMessage.sysData.type = (strcmp(_INIT(TOSTRING(APP)), "StarBase")==0)?1:(strcmp(_INIT(TOSTRING(APP)), "StarLeds")==0)?2:3; //1=StarBase,2=StarLeds, 3=StarFork

updateInstance(starMessage);
}
else if (packetSize == 500) { //StarBase upp json
else if (packetSize == 500) { //udp json message

char buffer[packetSize];
instanceUDP.read(buffer, packetSize);
Expand All @@ -486,7 +421,7 @@ class UserModInstances:public SysModule {

mdl->setValue(message["id"].as<const char *>(), message["value"].as<uint8_t>());

ppf("StarMod udp json read %s\n", buffer);
ppf("udp json read %s\n", buffer);

}
else {
Expand Down Expand Up @@ -553,39 +488,48 @@ class UserModInstances:public SysModule {
#endif
starMessage.header.insId = localIP[3]; //WLED: used in map of instances as index!
starMessage.header.version = VERSION;
starMessage.sys.type = (strcmp(_INIT(TOSTRING(APP)), "StarBase")==0)?1:(strcmp(_INIT(TOSTRING(APP)), "StarLeds")==0)?2:3; //1=StarBase,2=StarLeds, 3=StarFork
starMessage.sys.upTime = millis()/1000;
starMessage.sys.syncMaster = mdl->getValue("sma");
starMessage.sys.dmx.universe = 0;
starMessage.sys.dmx.start = 0;
starMessage.sys.dmx.count = 0;
starMessage.sysData.type = (strcmp(_INIT(TOSTRING(APP)), "StarBase")==0)?1:(strcmp(_INIT(TOSTRING(APP)), "StarLeds")==0)?2:3; //1=StarBase,2=StarLeds, 3=StarFork
starMessage.sysData.upTime = millis()/1000;
starMessage.sysData.syncMaster = mdl->getValue("sma");
starMessage.sysData.dmx.universe = 0;
starMessage.sysData.dmx.start = 0;
starMessage.sysData.dmx.count = 0;
#ifdef STARBASE_USERMOD_E131
if (e131mod->isEnabled) {
starMessage.sys.dmx.universe = mdl->getValue("dun");
starMessage.sys.dmx.start = mdl->getValue("dch");
starMessage.sys.dmx.count = 3;//e131->varsToWatch.size();
starMessage.sysData.dmx.universe = mdl->getValue("dun");
starMessage.sysData.dmx.start = mdl->getValue("dch");
starMessage.sysData.dmx.count = 3;//e131->varsToWatch.size();
}
#endif

//dash values default 0
starMessage.app.initVars();

//send dash values
mdl->findVars("dash", true, [&starMessage](JsonObject var) { //varFun
// print->printJson("setVar", var);
JsonArray valArray = mdl->varValArray(var);
if (valArray.isNull())
starMessage.app.setVar(var["id"], var["value"]);
else if (valArray.size())
starMessage.app.setVar(var["id"], valArray[0].as<byte>()); //set the first value (tbd: add multiple)
});

updateInstance(starMessage); //temp? to show own instance in list as instance is not catching it's own udp message...

IPAddress broadcastIP(255, 255, 255, 255);
if (0 != instanceUDP.beginPacket(broadcastIP, instanceUDPPort)) { // WLEDMM beginPacket == 0 --> error
//other way around: first set instance variables, then fill starMessage
for (InstanceInfo &instance: instances) {
if (instance.ip == WiFi.localIP()) {
instance.jsonData.to<JsonObject>(); //clear

//send dash values
mdl->findVars("dash", true, [&instance](JsonObject var) { //varFun
// print->printJson("setVar", var);
JsonArray valArray = mdl->varValArray(var);
if (valArray.isNull())
instance.jsonData[mdl->varID(var)] = var["value"];
else if (valArray.size())
instance.jsonData[mdl->varID(var)] = valArray;
});

serializeJson(instance.jsonData, starMessage.jsonString);
ppf("udp json String send ip:%d s:%s\n", instance.ip[3], starMessage.jsonString);
// print->printJson(" d:", instance.jsonData);
// print->printJDocInfo(" info", instance.jsonData);
}
}

// broadcast to network
if (0 != instanceUDP.beginPacket(IPAddress(255, 255, 255, 255), instanceUDPPort)) { // WLEDMM beginPacket == 0 --> error
// ppf("sendSysInfoUDP %s s:%d p:%d i:...%d\n", starMessage.header.name, sizeof(UDPStarMessage), instanceUDPPort, localIP[3]);
// for (size_t x = 0; x < sizeof(UDPWLEDMessage) + sizeof(SysData) + sizeof(AppData); x++) {
// for (size_t x = 0; x < sizeof(UDPWLEDMessage) + sizeof(SysData); x++) {
// char * xx = (char *)&starMessage;
// Serial.printf("%d: %d - %c\n", x, xx[x], xx[x]);
// }
Expand Down Expand Up @@ -614,66 +558,61 @@ class UserModInstances:public SysModule {
if (!instanceFound) { //new instance
InstanceInfo instance;
instance.ip = messageIP;
if (udpStarMessage.sys.type == 0) {//WLED only
instance.sys.type = 0; //WLED
if (udpStarMessage.sysData.type == 0) {//WLED only
instance.sysData.type = 0; //WLED
//updated in udp sync message:
instance.sys.upTime = 0;
instance.sys.dmx.universe = 0;
instance.sys.dmx.start = 0;
instance.sys.dmx.count = 0;
instance.sys.syncMaster = 0;
instance.sysData.upTime = 0;
instance.sysData.dmx.universe = 0;
instance.sysData.dmx.start = 0;
instance.sysData.dmx.count = 0;
instance.sysData.syncMaster = 0;
//dash values default 0
instance.app.initVars();
instance.jsonData.to<JsonObject>();
}

instances.push_back(instance);
std::sort(instances.begin(),instances.end(), [](InstanceInfo &a, InstanceInfo &b){ return a.ip < b.ip; });//Sorting the vector strcmp(a.name,b.name);
}

//iterate vector pointers so we can update the instances
//update the instance in the instances array with the message data

// stackUnsigned8 rowNr = 0;
for (InstanceInfo &instance: instances) {
if (instance.ip == messageIP) {
instance.timeStamp = millis(); //update timestamp
strncpy(instance.name, udpStarMessage.header.name, sizeof(instance.name)-1);
instance.version = udpStarMessage.header.version;
if (instance.ip == WiFi.localIP()) {
esp_wifi_get_mac((wifi_interface_t)ESP_IF_WIFI_STA, instance.macAddress);
esp_wifi_get_mac((wifi_interface_t)ESP_IF_WIFI_STA, instance.sysData.macAddress);
// ppf("macaddress %02X:%02X:%02X:%02X:%02X:%02X\n", instance.macAddress[0], instance.macAddress[1], instance.macAddress[2], instance.macAddress[3], instance.macAddress[4], instance.macAddress[5]);
}
if (udpStarMessage.sys.type >= 1) {//StarBase, StarLeds and forks only
instance.sys = udpStarMessage.sys;

//check for syncing
stackUnsigned8 syncMaster = mdl->getValue("sma");
if (syncMaster == messageIP[3]) {

//find matching var
for (int i=0; i< nrOfAppVars; i++) {
//set instance kv

VarData newVar = udpStarMessage.app.vars[i];

if (!instance.app.str3cmp(newVar.id, "-")) {

int value = instance.app.getVar(newVar.id);

//if no value found or value has changed
if (value == -1 || value != newVar.value) {
char varID[4];
instance.app.str3cpy(varID, newVar.id);
varID[3]='\0';

ppf("AppData3 %s %s %d\n", instance.name, varID, newVar.value);
mdl->setValue(varID, newVar.value);
if (udpStarMessage.sysData.type >= 1) {//StarBase, StarLeds and forks only
instance.sysData = udpStarMessage.sysData;

if (instance.ip != WiFi.localIP()) { //send from localIP will be done after updateInstance
//set instance.jsonData from new string
JsonDocument newData;
DeserializationError error = deserializeJson(newData, udpStarMessage.jsonString);
if (error || !newData.is<JsonObject>()) {
ppf("udp json String receive failed ip:%d e:%s\n", instance.ip[3], error.c_str(), udpStarMessage.jsonString);
}
else {
stackUnsigned8 syncMaster = mdl->getValue("sma");
if (syncMaster == messageIP[3]) { //if the message is from the master, set all values from the master
for (JsonPair pair: newData.as<JsonObject>()) {
if (pair.key() != "sma" && pair.key() != "dch") { // do not sync sma and dch !!!
ppf("updateInstance sync from i:%s k:%s v:%s\n", instance.name, pair.key().c_str(), pair.value().as<String>().c_str());
// if (mdl->getValue(pair.key().c_str) != pair.value())
mdl->setValue(pair.key().c_str(), pair.value());
}
}
}
}
}

//set values to instance
for (int i=0; i< nrOfAppVars; i++)
instance.app.vars[i] = udpStarMessage.app.vars[i];
instance.jsonData = newData; // deepcopy: https://github.com/bblanchon/ArduinoJson/issues/1023
ppf("udp json String receive ip:%d", instance.ip[3]);
print->printJson(" d:", instance.jsonData);
}
}
}

//only update cell in instbl!
Expand Down

0 comments on commit e1f0bf1

Please sign in to comment.