Mon, 15 Apr 2024 17:04:57 +0200
Better websocket broadcast messages. Added GLOBAL JSON command to the server. Better logic to trigger websocket and mqtt data updates for the fermenter units. Websocket receive added fermenter mode, stage, setpoints, switches. Added more css styles for the fermenter screen. Added the fermenter screen php and javascript.
/** * @brief One-wire devices * * Copyright (C) 2024 * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * mbsePi-apps is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MBSE BBS; see the file COPYING. If not, write to the Free * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ extern int debug; #include "thermferm.h" #include "statetbl.h" #include "one-wire.h" #include "devices.h" #include "delay.h" #include "futil.h" #include "xutil.h" #define W1_TEMP_RESOLUTION 12 extern sys_config Config; extern pthread_mutex_t mutexes[5]; int my_one_wire_state = 0; int my_one_wire_shutdown = 0; w1_list *w1_devices = NULL; static int one_wire(void); void *my_one_wire_loop(void *threadid) { my_one_wire_state = 1; syslog(LOG_NOTICE, "Thread my_one_wire_loop started"); /* * Run the state machine */ one_wire(); /* * Remove the dynamic tables. */ syslog(LOG_NOTICE, "Thread my_one_wire_loop stopped"); my_one_wire_state = 0; return 0; } SM_DECL(one_wire,(char *)"one-wire") SM_STATES ScanNew, ScanDel, Read2413, ReadTemp, Missing SM_NAMES (char *)"ScanNew", (char *)"ScanDel", (char *)"Read2413", (char *)"ReadTemp", (char *)"Missing" SM_EDECL int found, i, rc, value, conv_time; FILE *fp; devices_list *device; w1_list *dev_w1, *n_w1, *cur_w1 = NULL; char buffer[25], w1type[10], *devfile = NULL; uint8_t state, output, newval; SM_START(ScanNew) SM_STATE(ScanNew) if (my_one_wire_shutdown) { SM_SUCCESS; } /* * Scan for current one-wire devices. */ fp = fopen("/sys/devices/w1_bus_master1/w1_master_slaves", "r"); if (fp == NULL) { syslog(LOG_NOTICE, "No w1_bus_master: %s", strerror(errno)); SM_ERROR; } while ((fgets(buffer, 25, fp))) { buffer[strlen(buffer)-1] = '\0'; strncpy(w1type, buffer, 2); w1type[2] = '\0'; /* * Check if device is known and already detected. */ if ((strcmp(w1type, (char *)"3a") == 0) || (strcmp(w1type, (char *)"10") == 0) || (strcmp(w1type, (char *)"22") == 0) || (strcmp(w1type, (char *)"28") == 0) || (strcmp(w1type, (char *)"3b") == 0) || (strcmp(w1type, (char *)"42") == 0)) { found = FALSE; for (dev_w1 = w1_devices; dev_w1; dev_w1 = dev_w1->next) { if (strcmp(dev_w1->address, buffer) == 0) { found = TRUE; dev_w1->timestamp = time(NULL); if (dev_w1->present != DEVPRESENT_YES) { syslog(LOG_NOTICE, "One-wire device %s is back", buffer); pthread_mutex_lock(&mutexes[LOCK_ONE_WIRE]); dev_w1->present = DEVPRESENT_YES; pthread_mutex_unlock(&mutexes[LOCK_ONE_WIRE]); for (device = Config.devices; device; device = device->next) { if (strcmp(dev_w1->address, device->address) == 0) { // pthread_mutex_lock(&mutexes[LOCK_DEVICES]); device->present = DEVPRESENT_YES; // pthread_mutex_unlock(&mutexes[LOCK_DEVICES]); } } } break; } } if (found == FALSE) { syslog(LOG_NOTICE, "One-wire device %s add new", buffer); n_w1 = (w1_list *)malloc(sizeof(w1_list)); n_w1->next = NULL; n_w1->address = xstrcpy(buffer); strncpy(n_w1->family, buffer, 2); n_w1->family[2] = '\0'; n_w1->present = DEVPRESENT_YES; n_w1->value = (strcmp(w1type, (char *)"3a") == 0) ? 3:-1; n_w1->timestamp = time(NULL); pthread_mutex_lock(&mutexes[LOCK_ONE_WIRE]); if (w1_devices == NULL) { w1_devices = n_w1; cur_w1 = w1_devices; /* Point to first device */ } else { for (dev_w1 = w1_devices; dev_w1; dev_w1 = dev_w1->next) { if (dev_w1->next == NULL) { dev_w1->next = n_w1; break; } } } pthread_mutex_unlock(&mutexes[LOCK_ONE_WIRE]); } } else if (strcmp(w1type, (char *)"00")) { syslog(LOG_NOTICE, "One-wire device %ld %s unknown", strlen(buffer), buffer); } } fclose(fp); SM_PROCEED(ScanDel); SM_STATE(ScanDel) if (my_one_wire_shutdown) { SM_SUCCESS; } /* * Scan from the linked list if all devices are still present. */ for (dev_w1 = w1_devices; dev_w1; dev_w1 = dev_w1->next) { devfile = xstrcpy((char *)"/sys/bus/w1/devices/"); devfile = xstrcat(devfile, dev_w1->address); devfile = xstrcat(devfile, (char *)"/uevent"); if (file_exist(devfile, R_OK) && (dev_w1->present == DEVPRESENT_YES)) { /* * Gone missing */ syslog(LOG_NOTICE, "One-wire device %s is missing", dev_w1->address); pthread_mutex_lock(&mutexes[LOCK_ONE_WIRE]); dev_w1->present = DEVPRESENT_NO; pthread_mutex_unlock(&mutexes[LOCK_ONE_WIRE]); for (device = Config.devices; device; device = device->next) { if (strcmp(dev_w1->address, device->address) == 0) { // pthread_mutex_lock(&mutexes[LOCK_DEVICES]); device->present = DEVPRESENT_NO; // pthread_mutex_unlock(&mutexes[LOCK_DEVICES]); } } } free(devfile); devfile = NULL; } SM_PROCEED(Read2413); SM_STATE(Read2413) if (my_one_wire_shutdown) { SM_SUCCESS; } for (dev_w1 = w1_devices; dev_w1; dev_w1 = dev_w1->next) { if (strcmp(dev_w1->family, "3a") == 0) { for (i = 0; i < 2; i++) { for (device = Config.devices; device; device = device->next) { if ((strcmp(dev_w1->address, device->address) == 0) && (device->subdevice == i) && (device->direction == DEVDIR_IN_BIN)) { /* * First make sure that this device is configured as input * to drive the output high. Fix if programmed as output. */ if ((rc = read_w1(device->address, (char *)"state")) >= 0) { state = (unsigned int)rc; output = ((state & 0x02) >> 1) + ((state & 0x08) >> 2); /* Both latch states */ if ((i == 0) && ((state & 0x02) == 0)) { /* Fix A side */ syslog(LOG_NOTICE, "One-wire device %s-%d out %02x -> %02x", dev_w1->address, i, output, output | 0x01); output |= 0x01; write_w1(device->address, (char *)"output", output); mDelay(10); if ((rc = read_w1(device->address, (char *)"state")) >= 0) /* Read PIO again */ state = (unsigned int)rc; } if ((i == 1) && ((state & 0x08) == 0)) { /* Fix B side */ syslog(LOG_NOTICE, "One-wire device %s-%d out %02x -> %02x", dev_w1->address, i, output, output | 0x02); output |= 0x02; write_w1(device->address, (char *)"output", output); mDelay(10); if ((rc = read_w1(device->address, (char *)"state")) >= 0) /* Read PIO again */ state = (unsigned int)rc; } newval = ((state & 0x04) >> 1) + (state & 0x01); if (newval != dev_w1->value) { syslog(LOG_NOTICE, "One-wire device %s-%d in %02x value %d => %d", dev_w1->address, i, state, dev_w1->value, newval); dev_w1->value = newval; } // pthread_mutex_lock(&mutexes[LOCK_DEVICES]); /* * Read PIOA or PIOB pin state bits */ if (device->subdevice == 0) device->value = (state & 0x01) ? 0 : 1; else if (device->subdevice == 1) device->value = (state & 0x04) ? 0 : 1; device->timestamp = time(NULL); // pthread_mutex_unlock(&mutexes[LOCK_DEVICES]); } mDelay(20); } else if ((strcmp(dev_w1->address, device->address) == 0) && (device->subdevice == i) && (device->direction == DEVDIR_OUT_BIN)) { /* * Sync output state */ if ((rc = read_w1(device->address, (char *)"state")) >= 0) { state = (unsigned int)rc; newval = output = (state & 0x01) + ((state & 0x04) >> 1); if (device->subdevice == 0) { newval = (newval & 0xfe); newval |= (device->value) ? 0x00 : 0x01; } else if (device->subdevice == 1) { newval = (newval & 0xfd); newval |= (device->value) ? 0x00 : 0x02; } if (output != newval) { if ((write_w1(dev_w1->address, (char *)"output", newval)) == 0) { syslog(LOG_NOTICE, "One-wire device %s-%d out %02x -> %02x", dev_w1->address, i, output, newval); dev_w1->value = newval; } } } } } /* for (device = Config.devices; ... */ } } } SM_PROCEED(ReadTemp); SM_STATE(ReadTemp) if (my_one_wire_shutdown) { SM_SUCCESS; } /* * cur_w1 points to the next not handled device. */ if (cur_w1 != NULL) { if ((strcmp(cur_w1->family, (char *)"10") == 0) || (strcmp(cur_w1->family, (char *)"22") == 0) || (strcmp(cur_w1->family, (char *)"28") == 0) || (strcmp(cur_w1->family, (char *)"3b") == 0) || (strcmp(cur_w1->family, (char *)"42") == 0)) { devfile = xstrcpy((char *)"/sys/bus/w1/devices/"); devfile = xstrcat(devfile, cur_w1->address); devfile = xstrcat(devfile, (char *)"/resolution"); if ((fp = fopen(devfile, "r+"))) { if ((fgets(buffer, 25, fp))) { sscanf(buffer, "%d", &value); if (value != W1_TEMP_RESOLUTION) { syslog(LOG_NOTICE, "One-wire device %s set resolution from %d to %d", cur_w1->address, value, W1_TEMP_RESOLUTION); fseek(fp, 0L, SEEK_SET); sprintf(buffer, "%d", W1_TEMP_RESOLUTION); fputs(buffer, fp); } } fclose(fp); free(devfile); conv_time = 760; devfile = xstrcpy((char *)"/sys/bus/w1/devices/"); devfile = xstrcat(devfile, cur_w1->address); devfile = xstrcat(devfile, (char *)"/conv_time"); if ((fp = fopen(devfile, "r"))) { if ((fgets(buffer, 25, fp))) { sscanf(buffer, "%d", &conv_time); } fclose(fp); } free(devfile); devfile = xstrcpy((char *)"/sys/bus/w1/devices/"); devfile = xstrcat(devfile, cur_w1->address); devfile = xstrcat(devfile, (char *)"/temperature"); if ((fp = fopen(devfile, "r"))) { // syslog(LOG_NOTICE, "One-wire device %s temperature is open, delay %d", cur_w1->address, conv_time); mDelay(conv_time); if ((fgets(buffer, 25, fp))) { sscanf(buffer, "%d", &value); // if (cur_w1->value != value) // syslog(LOG_NOTICE, "One-wire device %s temperature read %d => %d", cur_w1->address, cur_w1->value, value); cur_w1->value = value; /* devices.c will pick this up */ } else { syslog(LOG_NOTICE, "One-wire device %s temperature read error", cur_w1->address); } fclose(fp); } } else { syslog(LOG_NOTICE, "One-wire device %s open: %s", cur_w1->address, strerror(errno)); } free(devfile); devfile = NULL; } for (;;) { if (cur_w1->next != NULL) { cur_w1 = cur_w1->next; } else { cur_w1 = w1_devices; } if ((strcmp(cur_w1->family, (char *)"10") == 0) || (strcmp(cur_w1->family, (char *)"22") == 0) || (strcmp(cur_w1->family, (char *)"28") == 0) || (strcmp(cur_w1->family, (char *)"3b") == 0) || (strcmp(cur_w1->family, (char *)"42") == 0)) break; } } else { mDelay(750); } SM_PROCEED(Missing); SM_STATE(Missing) if (my_one_wire_shutdown) { SM_SUCCESS; } sleep(1); SM_PROCEED(ScanNew); SM_END SM_RETURN