# HG changeset patch # User Michiel Broek # Date 1714657756 -7200 # Node ID 5c30c8ef83a8318ec193f81a3349f1f9b09f26c5 # Parent f5d85af156abee37b0578dd7b52e5d3ed3132c9b Version 0.9.19b3. The simulator thread can be paused to be able to add and delete simulators. Added simulated door and PSU status. Devices can now fully use multiple simulators. Better rounding of simulated temperature values. The server SIMULATOR DEL and ADD commands pause the simulator when the linked list is manipulated. Fixed SIGSEGV when a simulator is added. Added socket SO_REUSEADDR again to the server socket. diff -r f5d85af156ab -r 5c30c8ef83a8 configure --- a/configure Wed May 01 14:38:37 2024 +0200 +++ b/configure Thu May 02 15:49:16 2024 +0200 @@ -2037,7 +2037,7 @@ PACKAGE="mbsePi-apps" -VERSION="0.9.19b2" +VERSION="0.9.19b3" COPYRIGHT="Copyright (C) 2014-2024 Michiel Broek, All Rights Reserved" CYEARS="2014-2024" diff -r f5d85af156ab -r 5c30c8ef83a8 configure.ac --- a/configure.ac Wed May 01 14:38:37 2024 +0200 +++ b/configure.ac Thu May 02 15:49:16 2024 +0200 @@ -8,7 +8,7 @@ dnl General settings dnl After changeing the version number, run autoconf! PACKAGE="mbsePi-apps" -VERSION="0.9.19b2" +VERSION="0.9.19b3" COPYRIGHT="Copyright (C) 2014-2024 Michiel Broek, All Rights Reserved" CYEARS="2014-2024" AC_SUBST(PACKAGE) diff -r f5d85af156ab -r 5c30c8ef83a8 thermferm/devices.c --- a/thermferm/devices.c Wed May 01 14:38:37 2024 +0200 +++ b/thermferm/devices.c Thu May 02 15:49:16 2024 +0200 @@ -40,6 +40,9 @@ extern const char DEVPRESENT[4][6]; extern const char DEVDIR[7][11]; +#ifdef USE_SIMULATOR +extern int my_simulator_state; +#endif /* @@ -306,6 +309,7 @@ #ifdef USE_SIMULATOR if ((device->type == DEVTYPE_SIM) && (device->direction == DEVDIR_OUT_BIN)) { + while (my_simulator_state == THREAD_PAUSE) { mDelay(20); }; for (simulator = Config.simulators; simulator; simulator = simulator->next) { if ((strcmp(device->address, simulator->cooler_address) == 0) || (strcmp(device->address, simulator->heater_address) == 0) || @@ -715,20 +719,22 @@ #ifdef USE_SIMULATOR for (simulator = Config.simulators; simulator; simulator = simulator->next) { - for (i = 0; i < 10; i++) { + for (i = 0; i < 12; i++) { found = FALSE; for (device = Config.devices; device; device = device->next) { - if ((i == 0 && strcmp(device->address, simulator->room_tempaddress) == 0) || - (i == 1 && strcmp(device->address, simulator->air_address) == 0) || - (i == 2 && strcmp(device->address, simulator->beer_address) == 0) || - (i == 3 && strcmp(device->address, simulator->heater_address) == 0) || - (i == 4 && strcmp(device->address, simulator->cooler_address) == 0) || - (i == 5 && strcmp(device->address, simulator->room_humaddress) == 0) || - (i == 6 && strcmp(device->address, simulator->chiller_address) == 0) || - (i == 7 && strcmp(device->address, simulator->fan_address) == 0) || - (i == 8 && strcmp(device->address, simulator->light_address) == 0) || - (i == 9 && strcmp(device->address, simulator->beer_address2) == 0)) { + if ((i == 0 && strcmp(device->address, simulator->room_tempaddress) == 0) || + (i == 1 && strcmp(device->address, simulator->air_address) == 0) || + (i == 2 && strcmp(device->address, simulator->beer_address) == 0) || + (i == 3 && strcmp(device->address, simulator->heater_address) == 0) || + (i == 4 && strcmp(device->address, simulator->cooler_address) == 0) || + (i == 5 && strcmp(device->address, simulator->room_humaddress) == 0) || + (i == 6 && strcmp(device->address, simulator->chiller_address) == 0) || + (i == 7 && strcmp(device->address, simulator->fan_address) == 0) || + (i == 8 && strcmp(device->address, simulator->light_address) == 0) || + (i == 9 && strcmp(device->address, simulator->beer_address2) == 0) || + (i == 10 && strcmp(device->address, simulator->door_address) == 0) || + (i == 11 && strcmp(device->address, simulator->psu_address) == 0)) { found = TRUE; break; } @@ -800,6 +806,16 @@ ndev->description = xstrcpy((char *)"Simulated beer temperature (alt)"); ndev->present = simulator->beer_present2; break; + case 10: ndev->direction = DEVDIR_IN_BIN; + ndev->address = xstrcpy(simulator->door_address); + ndev->description = xstrcpy((char *)"Simulated fridge door"); + ndev->present = simulator->door_present; + break; + case 11: ndev->direction = DEVDIR_IN_BIN; + ndev->address = xstrcpy(simulator->psu_address); + ndev->description = xstrcpy((char *)"Simulated PSU status"); + ndev->present = simulator->psu_present; + break; } syslog(LOG_NOTICE, "New Simulator device %s, subdevice %d", ndev->address, ndev->subdevice); @@ -960,46 +976,60 @@ #endif #ifdef USE_SIMULATOR case DEVTYPE_SIM: + while (my_simulator_state == THREAD_PAUSE) { mDelay(20); }; // pthread_mutex_lock(&mutexes[LOCK_DEVICES]); - if (Config.simulators) { + for (simulator = Config.simulators; simulator; simulator = simulator->next) { int val; - simulator = Config.simulators; - if (device->subdevice == 0) { + if (strcmp(simulator->room_tempaddress, device->address) == 0) { val = (int)((int)(simulator->room_temperature * 1000) / 500) * 500; if (device->value != val) { device->value = val; device->timestamp = time(NULL); changed = true; } - } else if (device->subdevice == 1) { - val = (int)((int)(simulator->air_temperature * 1000) / 62.5) * 62.5; + } else if (strcmp(simulator->air_address, device->address) == 0) { + val = (int)((int)((simulator->air_temperature * 1000) + 31.25) / 62.5) * 62.5; if (device->value != val) { device->value = val; device->timestamp = time(NULL); changed = true; } - } else if (device->subdevice == 2) { - val = (int)((int)(simulator->beer_temperature * 1000) / 62.5) * 62.5; + } else if (strcmp(simulator->beer_address, device->address) == 0) { + val = (int)((int)((simulator->beer_temperature * 1000) + 31.25) / 62.5) * 62.5; if (device->value != val) { device->value = val; device->timestamp = time(NULL); changed = true; } - } else if (device->subdevice == 5) { + } else if (strcmp(simulator->room_humaddress, device->address) == 0) { val = (int)((int)(simulator->room_humidity * 1000) / 500) * 500; if (device->value != val) { device->value = val; device->timestamp = time(NULL); changed = true; } - } else if (device->subdevice == 6) { + } else if (strcmp(simulator->chiller_address, device->address) == 0) { val = (int)((int)(simulator->chiller_temperature * 1000) / 62.5) * 62.5; if (device->value != val) { device->value = val; device->timestamp = time(NULL); changed = true; } + } else if (strcmp(simulator->door_address, device->address) == 0) { + val = simulator->door_value; + if (device->value != val) { + device->value = val; + device->timestamp = time(NULL); + changed = true; + } + } else if (strcmp(simulator->psu_address, device->address) == 0) { + val = simulator->psu_value; + if (device->value != val) { + device->value = val; + device->timestamp = time(NULL); + changed = true; + } } } // pthread_mutex_unlock(&mutexes[LOCK_DEVICES]); diff -r f5d85af156ab -r 5c30c8ef83a8 thermferm/rdconfig.c --- a/thermferm/rdconfig.c Wed May 01 14:38:37 2024 +0200 +++ b/thermferm/rdconfig.c Thu May 02 15:49:16 2024 +0200 @@ -174,6 +174,10 @@ free(simulator->fan_address); if (simulator->light_address) free(simulator->light_address); + if (simulator->door_address) + free(simulator->door_address); + if (simulator->psu_address) + free(simulator->psu_address); free(simulator); } Config.simulators = NULL; @@ -487,6 +491,12 @@ xmlTextWriterWriteFormatElement(writer, BAD_CAST "LIGHT_ADDRESS", "%s", simulator->light_address); xmlTextWriterWriteFormatElement(writer, BAD_CAST "LIGHT_PRESENT", "%s", DEVPRESENT[simulator->light_present]); xmlTextWriterWriteFormatElement(writer, BAD_CAST "LIGHT_POWER", "%d", simulator->light_power); + xmlTextWriterWriteFormatElement(writer, BAD_CAST "DOOR_ADDRESS", "%s", simulator->door_address); + xmlTextWriterWriteFormatElement(writer, BAD_CAST "DOOR_PRESENT", "%s", DEVPRESENT[simulator->door_present]); + xmlTextWriterWriteFormatElement(writer, BAD_CAST "DOOR_VALUE", "%d", simulator->door_value); + xmlTextWriterWriteFormatElement(writer, BAD_CAST "PSU_ADDRESS", "%s", simulator->psu_address); + xmlTextWriterWriteFormatElement(writer, BAD_CAST "PSU_PRESENT", "%s", DEVPRESENT[simulator->psu_present]); + xmlTextWriterWriteFormatElement(writer, BAD_CAST "PSU_VALUE", "%d", simulator->psu_value); xmlTextWriterWriteFormatElement(writer, BAD_CAST "FRIGO_ISOLATION", "%.3f", simulator->frigo_isolation); xmlTextWriterWriteFormatElement(writer, BAD_CAST "TIMESTAMP", "%ld", (long)simulator->timestamp); xmlTextWriterWriteFormatElement(writer, BAD_CAST "S_YEAST_HEAT", "%f", simulator->s_yeast_heat); @@ -1379,6 +1389,7 @@ simulator->uuid = simulator->name = NULL; simulator->room_tempaddress = simulator->room_humaddress = simulator->air_address = simulator->beer_address = simulator->beer_address2 = NULL; simulator->chiller_address = simulator->cooler_address = simulator->heater_address = simulator->fan_address = simulator->light_address = NULL; + simulator->door_address = simulator->psu_address = NULL; simulator->simno = simulator->volume_air = simulator->volume_beer = 0; simulator->room_temperature = simulator->air_temperature = simulator->beer_temperature = simulator->s_cool_temp = simulator->s_heat_temp = 20.0; simulator->chiller_temperature = 1.5; @@ -1622,6 +1633,44 @@ simulator->light_power = ival; xmlFree(key); } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"DOOR_ADDRESS"))) { + simulator->door_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"DOOR_PRESENT"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + for (i = 0; i < 4; i++) { + if (! xmlStrcmp(key, (const xmlChar *)DEVPRESENT[i])) { + simulator->door_present = i; + break; + } + } + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"DOOR_VALUE"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%d", &ival) == 1) + simulator->door_value = ival; + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PSU_ADDRESS"))) { + simulator->psu_address = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PSU_PRESENT"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + for (i = 0; i < 4; i++) { + if (! xmlStrcmp(key, (const xmlChar *)DEVPRESENT[i])) { + simulator->psu_present = i; + break; + } + } + xmlFree(key); + } + if ((!xmlStrcmp(cur->name, (const xmlChar *)"PSU_VALUE"))) { + key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); + if (sscanf((const char *)key, "%d", &ival) == 1) + simulator->psu_value = ival; + xmlFree(key); + } if ((!xmlStrcmp(cur->name, (const xmlChar *)"FRIGO_ISOLATION"))) { key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1); if (sscanf((const char *)key, "%f", &fval) == 1) diff -r f5d85af156ab -r 5c30c8ef83a8 thermferm/server.c --- a/thermferm/server.c Wed May 01 14:38:37 2024 +0200 +++ b/thermferm/server.c Thu May 02 15:49:16 2024 +0200 @@ -958,6 +958,9 @@ #ifdef USE_SIMULATOR + +extern int my_simulator_command, my_simulator_state; + int delete_Simulator(char *uuid) { simulator_list *current = Config.simulators; @@ -968,16 +971,36 @@ if (previous == NULL) { Config.simulators = current->next; free(current->uuid); - current->uuid = NULL; +// current->uuid = NULL; free(current->name); - current->name = NULL; +// current->name = NULL; + free(current->air_address); + free(current->beer_address); + free(current->beer_address2); + free(current->chiller_address); + free(current->cooler_address); + free(current->heater_address); + free(current->fan_address); + free(current->light_address); + free(current->door_address); + free(current->psu_address); free(current); return 1; } else { free(current->uuid); - current->uuid = NULL; +// current->uuid = NULL; free(current->name); - current->name = NULL; +// current->name = NULL; + free(current->air_address); + free(current->beer_address); + free(current->beer_address2); + free(current->chiller_address); + free(current->cooler_address); + free(current->heater_address); + free(current->fan_address); + free(current->light_address); + free(current->door_address); + free(current->psu_address); previous->next = current->next; free(current); current = previous->next; @@ -1003,7 +1026,7 @@ int cmd_simulator(int s, char *buf) { char *opt, *param, *kwd, *val, ibuf[SS_BUFSIZE]; - simulator_list *simulator, *tmps; + simulator_list *simulator, *nsim; int rc, rlen, ival, i; float fval; uuid_t uu; @@ -1077,9 +1100,9 @@ * For now, only one simulator is allowed. */ if (Config.simulators) { - for (tmps = Config.simulators; tmps; tmps = tmps->next) { - if (tmps->simno > highno) - highno = tmps->simno; + for (simulator = Config.simulators; simulator; simulator = simulator->next) { + if (simulator->simno > highno) + highno = simulator->simno; count++; } } @@ -1088,73 +1111,99 @@ return 0; } - simulator = (simulator_list *)malloc(sizeof(simulator_list)); - simulator->next = NULL; - simulator->uuid = malloc(37); + my_simulator_command = THREAD_PAUSE; + while (my_simulator_state != THREAD_PAUSE) { mDelay(50); }; + syslog(LOG_NOTICE, "SIMULATOR ADD thread paused"); + + nsim = (simulator_list *)malloc(sizeof(simulator_list)); + memset(nsim, 0, sizeof(simulator_list)); + nsim->next = NULL; + nsim->uuid = malloc(37); uuid_generate(uu); - uuid_unparse(uu, simulator->uuid); - simulator->name = xstrcpy(param); - simulator->simno = highno + 1; - sprintf(abuf, "%d-", simulator->simno); - simulator->volume_air = 150; - simulator->volume_beer = 50; - simulator->room_tempaddress = xstrcpy(abuf); - simulator->room_tempaddress = xstrcat(simulator->room_tempaddress, (char *)"SimRoomTemp"); - simulator->room_temperature = simulator->air_temperature = simulator->beer_temperature = simulator->beer_temperature2 = 20.0; - simulator->s_cool_temp = simulator->s_heat_temp = 20.0; - simulator->room_humaddress = xstrcpy(abuf); - simulator->room_humaddress = xstrcat(simulator->room_humaddress, (char *)"SimRoomHum"); - simulator->room_humidity = 48.6; - simulator->air_address = xstrcpy(abuf); - simulator->air_address = xstrcat(simulator->air_address, (char *)"SimAirTemp"); - simulator->beer_address = xstrcpy(abuf); - simulator->beer_address = xstrcat(simulator->beer_address, (char *)"SimBeerTemp"); - simulator->beer_address2 = xstrcpy(abuf); - simulator->beer_address2 = xstrcat(simulator->beer_address2, (char *)"SimBeerTemp2"); - simulator->chiller_address = xstrcpy(abuf); - simulator->chiller_address = xstrcat(simulator->chiller_address, (char *)"SimChillerTemp"); - simulator->heater_address = xstrcpy(abuf); - simulator->heater_address = xstrcat(simulator->heater_address, (char *)"SimHeater"); - simulator->cooler_address = xstrcpy(abuf); - simulator->cooler_address = xstrcat(simulator->cooler_address, (char *)"SimCooler"); - simulator->fan_address = xstrcpy(abuf); - simulator->fan_address = xstrcat(simulator->fan_address, (char *)"SimFan"); - simulator->light_address = xstrcpy(abuf); - simulator->light_address = xstrcat(simulator->light_address, (char *)"SimLight"); - simulator->chiller_temperature = 1.5; /* Chiller temperature */ - simulator->cooler_temp = 1.5; /* Cooling temperature */ - simulator->cooler_time = 720; /* About 12 minutes for the cooler plate */ - simulator->cooler_size = 0.8; /* 0.8 square meter cooler plate */ - simulator->heater_temp = 150.0; /* Heating temperature */ - simulator->heater_time = 3; /* 3 seconds to heat-up */ - simulator->heater_size = 0.01; /* 0.01 square meter heater plate */ - simulator->air_present = simulator->beer_present = DEVPRESENT_YES; - simulator->beer_present2 = simulator->chiller_present = simulator->cooler_present = simulator->heater_present = DEVPRESENT_UNDEF; - simulator->frigo_isolation = 0.002; - simulator->timestamp = time(NULL); - simulator->s_yeast_heat = 0.0; - simulator->s_yeast_started = simulator->s_cool_changed = simulator->s_heat_changed = (int)0; + uuid_unparse(uu, nsim->uuid); + nsim->name = xstrcpy(param); + nsim->simno = highno + 1; + nsim->volume_air = 150; + nsim->volume_beer = 50; + snprintf(abuf, 63, "%d-%s", nsim->simno, (char *)"SimRoomTemp"); + nsim->room_tempaddress = xstrcpy(abuf); + nsim->room_temperature = nsim->air_temperature = nsim->beer_temperature = nsim->beer_temperature2 = 20.0; + nsim->s_cool_temp = nsim->s_heat_temp = 20.0; + snprintf(abuf, 63, "%d-%s", nsim->simno, (char *)"SimRoomHum"); + nsim->room_humaddress = xstrcpy(abuf); + nsim->room_humidity = 48.6; + snprintf(abuf, 63, "%d-%s", nsim->simno, (char *)"SimAirTemp"); + nsim->air_address = xstrcpy(abuf); + snprintf(abuf, 63, "%d-%s", nsim->simno, (char *)"SimBeerTemp"); + nsim->beer_address = xstrcpy(abuf); + snprintf(abuf, 63, "%d-%s", nsim->simno, (char *)"SimBeerTemp2"); + nsim->beer_address2 = xstrcpy(abuf); + snprintf(abuf, 63, "%d-%s", nsim->simno, (char *)"SimChillerTemp"); + nsim->chiller_address = xstrcpy(abuf); + snprintf(abuf, 63, "%d-%s", nsim->simno, (char *)"SimHeater"); + nsim->heater_address = xstrcpy(abuf); + snprintf(abuf, 63, "%d-%s", nsim->simno, (char *)"SimCooler"); + nsim->cooler_address = xstrcpy(abuf); + snprintf(abuf, 63, "%d-%s", nsim->simno, (char *)"SimFan"); + nsim->fan_address = xstrcpy(abuf); + snprintf(abuf, 63, "%d-%s", nsim->simno, (char *)"SimLight"); + nsim->light_address = xstrcpy(abuf); + snprintf(abuf, 63, "%d-%s", nsim->simno, (char *)"SimDoor"); + nsim->door_address = xstrcpy(abuf); + snprintf(abuf, 63, "%d-%s", nsim->simno, (char *)"SimPSU"); + nsim->psu_address = xstrcpy(abuf); + nsim->chiller_temperature = 1.5; /* Chiller temperature */ + nsim->cooler_temp = 1.5; /* Cooling temperature */ + nsim->cooler_time = 720; /* About 12 minutes for the cooler plate */ + nsim->cooler_size = 0.8; /* 0.8 square meter cooler plate */ + nsim->heater_temp = 150.0; /* Heating temperature */ + nsim->heater_time = 3; /* 3 seconds to heat-up */ + nsim->heater_size = 0.01; /* 0.01 square meter heater plate */ + nsim->door_value = nsim->psu_value = 0; + nsim->air_present = nsim->beer_present = DEVPRESENT_YES; + nsim->beer_present2 = nsim->chiller_present = nsim->cooler_present = nsim->heater_present = DEVPRESENT_UNDEF; + nsim->door_present = nsim->psu_present = DEVPRESENT_UNDEF; + nsim->frigo_isolation = 0.002; + nsim->timestamp = time(NULL); + nsim->s_yeast_heat = 0.0; + nsim->s_yeast_started = nsim->s_cool_changed = nsim->s_heat_changed = (int)0; if (Config.simulators == NULL) { - Config.simulators = simulator; + syslog(LOG_NOTICE, "SIMULATOR ADD root"); + Config.simulators = nsim; } else { - for (tmps = Config.simulators; tmps; tmps = tmps->next) { - if (tmps->next == NULL) { - tmps->next = simulator; + for (simulator = Config.simulators; simulator; simulator = simulator->next) { + syslog(LOG_NOTICE, "SIMULATOR ADD no %d %s", simulator->simno, simulator->name); + if (simulator->next == NULL) { + simulator->next = nsim; + syslog(LOG_NOTICE, "SIMULATOR ADD here"); break; } } } - syslog(LOG_NOTICE, "Simulator %s no %d added", simulator->uuid, simulator->simno); - srv_send(s, (char *)"211 Simulator %s added", simulator->uuid); + my_simulator_command = THREAD_RUN; + while (my_simulator_state != THREAD_RUN) { mDelay(50); }; + syslog(LOG_NOTICE, "SIMULATOR ADD thread runs"); + + syslog(LOG_NOTICE, "Simulator %s no %d added", param, highno + 1); + srv_send(s, (char *)"211 Simulator %s added", param); return 1; } if (strcmp(opt, (char *)"DEL") == 0) { // TODO: check devices in use. // TODO: delete simulated devices. + syslog(LOG_NOTICE, "Simulator DEL %s", param); + + my_simulator_command = THREAD_PAUSE; + while (my_simulator_state != THREAD_PAUSE) { mDelay(50); }; + syslog(LOG_NOTICE, "SIMULATOR DEL thread paused"); rc = delete_Simulator(param); + my_simulator_command = THREAD_RUN; + while (my_simulator_state != THREAD_RUN) { mDelay(50); }; + syslog(LOG_NOTICE, "SIMULATOR DEL thread runs"); + if (rc) { syslog(LOG_NOTICE, "Simulator %s deleted", param); srv_send(s, (char *)"211 Simulator %s deleted", param); @@ -1207,6 +1256,12 @@ srv_send(s, (char *)"LIGHT_ADDRESS,%s", simulator->light_address); srv_send(s, (char *)"LIGHT_PRESENT,%s", DEVPRESENT[simulator->light_present]); srv_send(s, (char *)"LIGHT_POWER,%d", simulator->light_power); + srv_send(s, (char *)"DOOR_ADDRESS,%s", simulator->door_address); + srv_send(s, (char *)"DOOR_PRESENT,%s", DEVPRESENT[simulator->door_present]); + srv_send(s, (char *)"DOOR_VALUE,%d", simulator->door_value); + srv_send(s, (char *)"PSU_ADDRESS,%s", simulator->psu_address); + srv_send(s, (char *)"PSU_PRESENT,%s", DEVPRESENT[simulator->psu_present]); + srv_send(s, (char *)"PSU_VALUE,%d", simulator->psu_value); srv_send(s, (char *)"FRIGO_ISOLATION,%.3f", simulator->frigo_isolation); srv_send(s, (char *)"TIMESTAMP,%ld", (long)simulator->timestamp); srv_send(s, (char *)"."); @@ -1457,6 +1512,40 @@ simulator->light_power = ival; } + } else if (strcmp(kwd, (char *)"DOOR_PRESENT") == 0) { + for (i = 0; i < 4; i++) { + if (strcmp(val, DEVPRESENT[i]) == 0) { + if (simulator->door_present != i) + syslog(LOG_NOTICE, "Simulator %s door_present %s to %s", simulator->uuid, DEVPRESENT[simulator->door_present], DEVPRESENT[i]); + simulator->door_present = i; + device_present(simulator->door_address, i); + break; + } + } + + } else if (strcmp(kwd, (char *)"DOOR_VALUE") == 0) { + ival = (strcmp(val, (char *)"true")) ? 0:1; + if (simulator->door_value != ival) + syslog(LOG_NOTICE, "Simulator %s door value %d to %d", simulator->uuid, simulator->door_value, ival); + simulator->door_value = ival; + + } else if (strcmp(kwd, (char *)"PSU_PRESENT") == 0) { + for (i = 0; i < 4; i++) { + if (strcmp(val, DEVPRESENT[i]) == 0) { + if (simulator->psu_present != i) + syslog(LOG_NOTICE, "Simulator %s psu_present %s to %s", simulator->uuid, DEVPRESENT[simulator->psu_present], DEVPRESENT[i]); + simulator->psu_present = i; + device_present(simulator->psu_address, i); + break; + } + } + + } else if (strcmp(kwd, (char *)"PSU_VALUE") == 0) { + ival = (strcmp(val, (char *)"true")) ? 0:1; + if (simulator->psu_value != ival) + syslog(LOG_NOTICE, "Simulator %s psu value %d to %d", simulator->uuid, simulator->psu_value, ival); + simulator->psu_value = ival; + } else if (strcmp(kwd, (char *)"FRIGO_ISOLATION") == 0) { if (sscanf(val, "%f", &fval) == 1) { if (simulator->frigo_isolation != fval) @@ -2264,7 +2353,8 @@ if ((unit->mode == UNITMODE_OFF) && (i != UNITMODE_OFF)) { unit->mqtt_flag |= MQTT_FLAG_BIRTH; } - syslog(LOG_NOTICE, "Fermenter unit %s mode %s to %s", unit->uuid, UNITMODE[unit->mode], UNITMODE[i]); + if (unit->mode != i) + syslog(LOG_NOTICE, "Fermenter unit %s mode %s to %s", unit->uuid, UNITMODE[unit->mode], UNITMODE[i]); unit->mode = i; /* Allways turn everything off after a mode change */ unit->PID_cool->OutP = unit->PID_heat->OutP = 0.0; @@ -2586,12 +2676,12 @@ return 0; } -// if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) { -// syslog(LOG_NOTICE, "Can't setsockopt SO_REUSEADDR socket: %s", strerror(errno)); -// close(ls); -// my_server_state = 0; -// return 0; -// } + if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) { + syslog(LOG_NOTICE, "Can't setsockopt SO_REUSEADDR socket: %s", strerror(errno)); + close(ls); + my_server_state = 0; + return 0; + } if (bind(ls, (struct sockaddr *)&myaddr_in, sizeof(struct sockaddr_in)) == -1) { syslog(LOG_NOTICE, "Can't bind to listen socket: %s", strerror(errno)); diff -r f5d85af156ab -r 5c30c8ef83a8 thermferm/simulator.c --- a/thermferm/simulator.c Wed May 01 14:38:37 2024 +0200 +++ b/thermferm/simulator.c Thu May 02 15:49:16 2024 +0200 @@ -29,14 +29,15 @@ #include "websocket.h" #include "simulator.h" -int my_simulator_state = 0; +int my_simulator_state = THREAD_OFF; +int my_simulator_command = THREAD_OFF; + #ifdef USE_SIMULATOR extern sys_config Config; extern const char DEVPRESENT[4][6]; -int my_simulator_shutdown = 0; static int simulate(void); @@ -154,6 +155,22 @@ payload = xstrcat(payload, (char *)"\",\"power\":"); sprintf(buf, "%d", simulator->light_power); payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)"},\"door\":{\"address\":\""); + + payload = xstrcat(payload, simulator->door_address); + payload = xstrcat(payload, (char *)"\",\"present\":\""); + payload = xstrcat(payload, (char *)DEVPRESENT[simulator->door_present]); + payload = xstrcat(payload, (char *)"\",\"value\":"); + sprintf(buf, "%d", simulator->door_value); + payload = xstrcat(payload, buf); + payload = xstrcat(payload, (char *)"},\"psu\":{\"address\":\""); + + payload = xstrcat(payload, simulator->psu_address); + payload = xstrcat(payload, (char *)"\",\"present\":\""); + payload = xstrcat(payload, (char *)DEVPRESENT[simulator->psu_present]); + payload = xstrcat(payload, (char *)"\",\"value\":"); + sprintf(buf, "%d", simulator->psu_value); + payload = xstrcat(payload, buf); payload = xstrcat(payload, (char *)"},\"frigo_isolation\":"); sprintf(buf, "%.4f", simulator->frigo_isolation); @@ -195,7 +212,7 @@ void *my_simulator_loop(void *threadid) { - my_simulator_state = 1; + my_simulator_command = THREAD_RUN; syslog(LOG_NOTICE, "Thread my_simulator_loop started"); /* @@ -204,7 +221,6 @@ simulate(); syslog(LOG_NOTICE, "Thread my_simulator_loop stopped"); - my_simulator_state = 0; return 0; } @@ -212,11 +228,13 @@ SM_DECL(simulate, (char *)"simulator") SM_STATES Init, + Pause, Waiting, Run, Websocket SM_NAMES (char *)"Init", + (char *)"Pause", (char *)"Waiting", (char *)"run", (char *)"Websocket" @@ -239,13 +257,28 @@ */ simulator->s_heat_temp = simulator->s_cool_temp = simulator->room_temperature; } + my_simulator_state = THREAD_RUN; SM_PROCEED(Waiting); +SM_STATE(Pause) + + my_simulator_state = THREAD_PAUSE; + if (my_simulator_command == THREAD_OFF) { + SM_SUCCESS; + } else if (my_simulator_command == THREAD_RUN) { + my_simulator_state = THREAD_RUN; + SM_PROCEED(Waiting); + } + mDelay(50); + SM_STATE(Waiting) - if (my_simulator_shutdown) { + if (my_simulator_command == THREAD_OFF) { SM_SUCCESS; + } else if (my_simulator_command == THREAD_PAUSE) { + SM_PROCEED(Pause); } + now = time(NULL); if (now != last) { last = now; @@ -258,8 +291,10 @@ changed = false; for (simulator = Config.simulators; simulator; simulator = simulator->next) { - if (my_simulator_shutdown) { + if (my_simulator_command == THREAD_OFF) { SM_SUCCESS; + } else if (my_simulator_command == THREAD_PAUSE) { + SM_PROCEED(Pause); } /* @@ -347,8 +382,10 @@ SM_STATE(Websocket) - if (my_simulator_shutdown) { + if (my_simulator_command == THREAD_OFF) { SM_SUCCESS; + } else if (my_simulator_command == THREAD_PAUSE) { + SM_PROCEED(Pause); } if (changed) { simulator_ws(); @@ -357,6 +394,9 @@ SM_PROCEED(Waiting); SM_END + + my_simulator_state = THREAD_OFF; + SM_RETURN diff -r f5d85af156ab -r 5c30c8ef83a8 thermferm/thermferm.c --- a/thermferm/thermferm.c Wed May 01 14:38:37 2024 +0200 +++ b/thermferm/thermferm.c Thu May 02 15:49:16 2024 +0200 @@ -62,7 +62,7 @@ extern int my_ws_shutdown; extern int my_simulator_state; #ifdef USE_SIMULATOR -extern int my_simulator_shutdown; +extern int my_simulator_command; #endif extern int my_one_wire_state; extern int my_one_wire_shutdown; @@ -1869,9 +1869,9 @@ my_shutdown = my_reboot = FALSE; my_devices_shutdown = my_panel_shutdown = my_server_shutdown = my_ws_shutdown = my_one_wire_shutdown = 0; my_devices_state = my_panel_state = my_server_state = my_ws_state = my_one_wire_state = 0; - my_simulator_state = 0; + my_simulator_state = THREAD_OFF; #ifdef USE_SIMULATOR - my_simulator_shutdown = 0; + my_simulator_command = THREAD_OFF; #endif if (lockprog((char *)"thermferm")) { syslog(LOG_NOTICE, "Can't lock"); @@ -2026,8 +2026,8 @@ * Stop threads */ #ifdef USE_SIMULATOR - my_simulator_shutdown = 1; - while (my_simulator_state) { mDelay(50); }; + my_simulator_command = THREAD_OFF; + while (my_simulator_state != THREAD_OFF) { mDelay(50); }; #endif my_panel_shutdown = 1; while (my_panel_state) { mDelay(50); }; diff -r f5d85af156ab -r 5c30c8ef83a8 thermferm/thermferm.h --- a/thermferm/thermferm.h Wed May 01 14:38:37 2024 +0200 +++ b/thermferm/thermferm.h Thu May 02 15:49:16 2024 +0200 @@ -63,6 +63,14 @@ /* + * Thread states + */ +#define THREAD_OFF 0 +#define THREAD_RUN 1 +#define THREAD_PAUSE 2 + + +/* * Frontpanel menu numbers */ #define MENU_NONE 0 @@ -367,6 +375,12 @@ char *light_address; /* Simulated interior light */ int light_present; int light_power; + char *door_address; /* Simulated fridge door */ + int door_present; + int door_value; + char *psu_address; /* Simulated PSU status */ + int psu_present; + int psu_value; float frigo_isolation; /* Frigo isolation value */ time_t timestamp; diff -r f5d85af156ab -r 5c30c8ef83a8 www/dbsimulators.php --- a/www/dbsimulators.php Wed May 01 14:38:37 2024 +0200 +++ b/www/dbsimulators.php Thu May 02 15:49:16 2024 +0200 @@ -80,6 +80,10 @@ $cmd .= "FAN_POWER," . $_POST['fan_power'] . "\r\n"; $cmd .= "LIGHT_PRESENT," . $_POST['light_present'] . "\r\n"; $cmd .= "LIGHT_POWER," . $_POST['light_power'] . "\r\n"; + $cmd .= "DOOR_PRESENT," . $_POST['door_present'] . "\r\n"; + $cmd .= "DOOR_VALUE," . $_POST['door_value'] . "\r\n"; + $cmd .= "PSU_PRESENT," . $_POST['psu_present'] . "\r\n"; + $cmd .= "PSU_VALUE," . $_POST['psu_value'] . "\r\n"; $cmd .= "FRIGO_ISOLATION," . $_POST['frigo_isolation'] . "\r\n"; $cmd .= "."; $answer = send_cmd($cmd); diff -r f5d85af156ab -r 5c30c8ef83a8 www/js/set_simulators.js --- a/www/js/set_simulators.js Wed May 01 14:38:37 2024 +0200 +++ b/www/js/set_simulators.js Thu May 02 15:49:16 2024 +0200 @@ -110,6 +110,12 @@ { name: 'light_address', map: 'light>address' }, { name: 'light_present', map: 'light>present' }, { name: 'light_power', map: 'light>power', type: 'int' }, + { name: 'door_address', map: 'door>address' }, + { name: 'door_present', map: 'door>present' }, + { name: 'door_value', map: 'door>value', type: 'int' }, + { name: 'psu_address', map: 'psu>address' }, + { name: 'psu_present', map: 'psu>present' }, + { name: 'psu_value', map: 'psu>value', type: 'int' }, { name: 'frigo_isolation', type: 'float' }, { name: 'timestamp', type: 'int' } ], @@ -121,7 +127,7 @@ tzoffset = (new Date()).getTimezoneOffset() * 60000; //offset in milliseconds // initialize the input fields. - $('#name').jqxInput({ theme: theme, width: 180, height: 23 }); + $('#name').jqxInput({ theme: theme, width: 240, height: 23 }); $('#simno').jqxNumberInput(Show0dec); $('#uuid').jqxInput({ theme: theme, width: 360, height: 23 }); $('#room_temperature,#room_humidity').jqxNumberInput(Perc1dec); @@ -129,9 +135,9 @@ $('#frigo_isolation').jqxNumberInput(Spin3dec); $('#timestamp').jqxInput({ theme: theme, width: 180, height: 23 }); - $('#air_address,#beer_address,#beer_address2,#chiller_address,#cooler_address,#heater_address,#fan_address,#light_address').jqxInput({ theme: theme, width: 180, height: 23 }); + $('#air_address,#beer_address,#beer_address2,#chiller_address,#cooler_address,#heater_address,#fan_address,#light_address,#door_address,#psu_address').jqxInput({ theme: theme, width: 180, height: 23 }); $('#air_temperature,#beer_temperature,#beer_temperature2,#chiller_temperature').jqxNumberInput(Show4dec); - $('#air_present,#beer_present,#beer_present2,#chiller_present,#cooler_present,#heater_present,#fan_present,#light_present').jqxDropDownList({ + $('#air_present,#beer_present,#beer_present2,#chiller_present,#cooler_present,#heater_present,#fan_present,#light_present,#door_present,#psu_present').jqxDropDownList({ theme: theme, source: DevicePresentAdapter, valueMember: 'mno', @@ -144,6 +150,8 @@ $('#cooler_temp,#heater_temp').jqxNumberInput(Spin1dec); $('#cooler_time,#heater_time').jqxNumberInput(PosInt); $('#cooler_size,#heater_size').jqxNumberInput(Spin4dec); + $('#door_value').jqxSwitchButton({ height: 23, width: 100, theme: theme }); + $('#psu_value').jqxSwitchButton({ height: 23, width: 100, theme: theme }); // initialize jqxGrid $('#jqxgrid').jqxGrid({ @@ -250,6 +258,12 @@ $('#light_address').val(dataRecord.light_address); $('#light_power').val(dataRecord.light_power); $('#light_present').val(dataRecord.light_present); + $('#door_address').val(dataRecord.door_address); + $('#door_value').val(dataRecord.door_value); + $('#door_present').val(dataRecord.door_present); + $('#psu_address').val(dataRecord.psu_address); + $('#psu_value').val(dataRecord.psu_value); + $('#psu_present').val(dataRecord.psu_present); var date = new Date((dataRecord.timestamp * 1000) - tzoffset).toISOString().slice(0, 19).replace("T", " "); $('#timestamp').val(date); // show the popup window. @@ -275,31 +289,29 @@ }); $('#Delete').jqxButton({ template: 'danger', width: '90px', theme: theme }); $('#Delete').click(function() { - if (editrow >= 0) { - // Open a popup to confirm this action. - $('#eventWindow').jqxWindow('open'); - $('#delOk').click(function() { - var data, - data = 'del=true&uuid=' + $('#dev_uuid').val(); - $.ajax({ - dataType: 'json', - url: url, - cache: false, - data: data, - type: 'POST', - success: function(data) { - if (data.error) { - console.log('del: ' + data.msg); - alert('Error: ' + data.msg); - } else { - console.log('del: success'); - } - }, - error: function(jqXHR, textStatus, errorThrown) {} - }); - $('#jqxgrid').jqxGrid('updatebounddata'); + // Open a popup to confirm this action. + $('#eventWindow').jqxWindow('open'); + $('#delOk').click(function() { + var data, + data = 'del=true&uuid=' + $('#uuid').val(); + $.ajax({ + dataType: 'json', + url: url, + cache: false, + data: data, + type: 'POST', + success: function(data) { + if (data.error) { + console.log('del: ' + data.msg); + alert('Error: ' + data.msg); + } else { + console.log('del: success'); + } + }, + error: function(jqXHR, textStatus, errorThrown) {} }); - } + $('#jqxgrid').jqxGrid('updatebounddata'); + }); $('#popupWindow').jqxWindow('hide'); }); $('#Cancel').jqxButton({ template: 'primary', width: '90px', theme: theme }); @@ -331,6 +343,10 @@ fan_power: parseInt($('#fan_power').jqxNumberInput('decimal')), light_present: $('#light_present').val(), light_power: parseInt($('#light_power').jqxNumberInput('decimal')), + door_present: $('#door_present').val(), + door_value: $('#door_value').val(), + psu_present: $('#psu_present').val(), + psu_value: $('#psu_value').val(), frigo_isolation: parseFloat($('#frigo_isolation').jqxNumberInput('decimal')) }; data = 'update=true&' + $.param(row); diff -r f5d85af156ab -r 5c30c8ef83a8 www/set_simulators.php --- a/www/set_simulators.php Wed May 01 14:38:37 2024 +0200 +++ b/www/set_simulators.php Thu May 02 15:49:16 2024 +0200 @@ -131,10 +131,26 @@
- + + Door address: + + Value: +
+ Present: +
+ + + + PSU address: + + Value: +
+ Present: +
+ + - - +