chore: debloat (remove platformio), onewire improvements
Squashed commit of the following: commit 5f16309f629b9928d2134b85ae64af69bc3ebbcd Author: kuwoyuki <kuwoyuki@cock.li> Date: Sun Nov 24 22:55:15 2024 +0600 fix: Makefile, improve onewire retries commit 55496a3bda941b52ff349dc75c9c06eb5a37c07d Author: kuwoyuki <kuwoyuki@cock.li> Date: Mon Nov 18 00:41:18 2024 +0600 fix: make onewire validity less strict commit 3428a9bc9792508972ce3e7e4e35a64f047bca10 Author: kuwoyuki <kuwoyuki@cock.li> Date: Sun Nov 17 23:57:55 2024 +0600 chore: rm bins commit 1594e5ed430522b15466c8afa62ff7fb1b28947c Author: kuwoyuki <kuwoyuki@cock.li> Date: Sun Nov 17 23:32:01 2024 +0600 chore: unplatformiofy
This commit is contained in:
373
onewire_temp.c
Normal file
373
onewire_temp.c
Normal file
@@ -0,0 +1,373 @@
|
||||
#include "onewire_temp.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "onewire.h"
|
||||
#include "systick.h"
|
||||
|
||||
#define ONEWIRE_CONVERSION_TIME_MS 750
|
||||
#define ONEWIRE_MAX_RETRIES 255
|
||||
|
||||
typedef struct {
|
||||
uint8_t address[8];
|
||||
float temperature;
|
||||
onewire_state_t state;
|
||||
uint32_t convert_start_time;
|
||||
bool valid;
|
||||
uint8_t error_count;
|
||||
uint32_t last_success_time;
|
||||
} onewire_sensor_t;
|
||||
|
||||
typedef struct {
|
||||
onewire_sensor_t sensors[ONEWIRE_MAX_SENSORS];
|
||||
uint8_t count;
|
||||
bool parallel_mode;
|
||||
} onewire_system_t;
|
||||
|
||||
static onewire_system_t ow_sys = {0};
|
||||
|
||||
void onewire_temp_init(void) {
|
||||
uint8_t addr[8];
|
||||
|
||||
OneWireBegin();
|
||||
OneWireResetSearch();
|
||||
|
||||
while (ow_sys.count < ONEWIRE_MAX_SENSORS) {
|
||||
if (!OneWireSearch(addr, true)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Validate sensor
|
||||
if (OneWireCrc8(addr, 7) != addr[7]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if it's a temperature sensor
|
||||
switch (addr[0]) {
|
||||
case 0x10: // DS18S20
|
||||
case 0x28: // DS18B20
|
||||
case 0x22: // DS1822
|
||||
break;
|
||||
default:
|
||||
continue; // Not a supported temperature sensor
|
||||
}
|
||||
|
||||
// Store valid sensor
|
||||
onewire_sensor_t* sensor = &ow_sys.sensors[ow_sys.count];
|
||||
memcpy(sensor->address, addr, 8);
|
||||
sensor->valid = true;
|
||||
sensor->state = ONEWIRE_STATE_READY;
|
||||
sensor->temperature = ONEWIRE_TEMP_INVALID;
|
||||
sensor->error_count = 0;
|
||||
sensor->last_success_time = millis();
|
||||
ow_sys.count++;
|
||||
}
|
||||
}
|
||||
|
||||
static float convert_temperature(const uint8_t* data, uint8_t family_code) {
|
||||
int16_t raw = (data[1] << 8) | data[0];
|
||||
|
||||
// DS18S20
|
||||
if (family_code == 0x10) {
|
||||
raw = raw << 3;
|
||||
if (data[7] == 0x10) {
|
||||
raw = (raw & 0xFFF0) + 12 - data[6];
|
||||
}
|
||||
}
|
||||
// DS18B20/DS1822
|
||||
else {
|
||||
switch (data[4] & 0x60) {
|
||||
case 0x00:
|
||||
raw &= ~7;
|
||||
break; // 9-bit
|
||||
case 0x20:
|
||||
raw &= ~3;
|
||||
break; // 10-bit
|
||||
case 0x40:
|
||||
raw &= ~1;
|
||||
break; // 11-bit
|
||||
}
|
||||
}
|
||||
|
||||
return (float)(raw / 16.0);
|
||||
}
|
||||
|
||||
static bool start_conversion(onewire_sensor_t* sensor) {
|
||||
if (!sensor->state != ONEWIRE_STATE_READY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!OneWireReset()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OneWireSelect(sensor->address);
|
||||
OneWireWrite(0x44, 0); // Start conversion w/o parasite power
|
||||
sensor->state = ONEWIRE_STATE_CONVERTING;
|
||||
sensor->convert_start_time = millis();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool read_temperature(onewire_sensor_t* sensor) {
|
||||
uint8_t data[9];
|
||||
|
||||
if (!OneWireReset()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OneWireSelect(sensor->address);
|
||||
OneWireWrite(0xBE, 0); // Read scratchpad
|
||||
OneWireReadBytes(data, 9);
|
||||
|
||||
if (OneWireCrc8(data, 8) != data[8]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sensor->temperature = convert_temperature(data, sensor->address[0]);
|
||||
sensor->error_count = 0;
|
||||
sensor->last_success_time = millis();
|
||||
return true;
|
||||
}
|
||||
|
||||
void onewire_temp_process(void) {
|
||||
uint32_t now = millis();
|
||||
|
||||
for (uint8_t i = 0; i < ow_sys.count; i++) {
|
||||
onewire_sensor_t* sensor = &ow_sys.sensors[i];
|
||||
|
||||
if (!sensor->valid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (sensor->state) {
|
||||
case ONEWIRE_STATE_READY:
|
||||
if (!ow_sys.parallel_mode) {
|
||||
if (!start_conversion(sensor)) {
|
||||
sensor->error_count++;
|
||||
if (sensor->error_count >= ONEWIRE_MAX_RETRIES) {
|
||||
sensor->valid = false;
|
||||
DEBUG_PRINT("sensor %d marked temporarily invalid after %d retries\n", i, ONEWIRE_MAX_RETRIES);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ONEWIRE_STATE_CONVERTING:
|
||||
if (now - sensor->convert_start_time >= ONEWIRE_CONVERSION_TIME_MS) {
|
||||
sensor->state = ONEWIRE_STATE_READ;
|
||||
}
|
||||
break;
|
||||
|
||||
case ONEWIRE_STATE_READ:
|
||||
if (!read_temperature(sensor)) {
|
||||
sensor->error_count++;
|
||||
if (sensor->error_count >= ONEWIRE_MAX_RETRIES) {
|
||||
sensor->valid = false;
|
||||
DEBUG_PRINT("sensor %d marked temporarily invalid after %d retries\n", i, ONEWIRE_MAX_RETRIES);
|
||||
}
|
||||
} else {
|
||||
sensor->valid = true; // re-enable
|
||||
sensor->error_count = 0;
|
||||
}
|
||||
sensor->state = ONEWIRE_STATE_READY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onewire_temp_start_parallel(void) {
|
||||
if (!OneWireReset()) {
|
||||
return;
|
||||
}
|
||||
|
||||
OneWireSkip(); // Address all devices
|
||||
OneWireWrite(0x44, 1); // Start conversion with parasite power
|
||||
|
||||
uint32_t now = millis();
|
||||
for (uint8_t i = 0; i < ow_sys.count; i++) {
|
||||
if (ow_sys.sensors[i].valid) {
|
||||
ow_sys.sensors[i].state = ONEWIRE_STATE_CONVERTING;
|
||||
ow_sys.sensors[i].convert_start_time = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float onewire_temp_get(uint8_t index) {
|
||||
return (index < ow_sys.count && ow_sys.sensors[index].valid)
|
||||
? ow_sys.sensors[index].temperature
|
||||
: ONEWIRE_TEMP_INVALID;
|
||||
}
|
||||
|
||||
uint8_t onewire_temp_count(void) { return ow_sys.count; }
|
||||
|
||||
const uint8_t* onewire_temp_address(uint8_t index) {
|
||||
return (index < ow_sys.count) ? ow_sys.sensors[index].address : NULL;
|
||||
}
|
||||
|
||||
bool onewire_temp_valid(uint8_t index) {
|
||||
return (index < ow_sys.count) ? ow_sys.sensors[index].valid : false;
|
||||
}
|
||||
|
||||
void onewire_temp_set_parallel(bool enable) { ow_sys.parallel_mode = enable; }
|
||||
|
||||
// MQTT
|
||||
void onewire_temp_publish_discovery(MQTTClient* client, const char* node_id) {
|
||||
char topic[MAX_TOPIC_LENGTH];
|
||||
char sensor_name[32];
|
||||
uint8_t sensor_count = onewire_temp_count();
|
||||
|
||||
// append to node list
|
||||
size_t current_len = strlen(nodes_list);
|
||||
char* ptr = nodes_list + current_len;
|
||||
size_t remaining = sizeof(nodes_list) - current_len;
|
||||
|
||||
for (uint8_t i = 0; i < sensor_count && remaining > 1; i++) {
|
||||
if (!onewire_temp_valid(i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// , if not 1st
|
||||
if (current_len > 0 && remaining > 1) {
|
||||
*ptr++ = ',';
|
||||
remaining--;
|
||||
current_len++;
|
||||
}
|
||||
|
||||
const uint8_t* addr = onewire_temp_address(i);
|
||||
int written = snprintf(sensor_name, sizeof(sensor_name),
|
||||
"temp_%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
addr[0], addr[1], addr[2], addr[3],
|
||||
addr[4], addr[5], addr[6], addr[7]);
|
||||
|
||||
if (written < 0 || (size_t)written >= remaining) {
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(ptr, sensor_name, written);
|
||||
ptr += written;
|
||||
remaining -= written;
|
||||
current_len += written;
|
||||
}
|
||||
*ptr = '\0';
|
||||
|
||||
// pub node list
|
||||
snprintf(topic, sizeof(topic), "homie/%s/$nodes", node_id);
|
||||
publish_retained(client, topic, nodes_list);
|
||||
|
||||
for (uint8_t i = 0; i < sensor_count; i++) {
|
||||
if (!onewire_temp_valid(i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint8_t* addr = onewire_temp_address(i);
|
||||
snprintf(sensor_name, sizeof(sensor_name),
|
||||
"temp_%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
addr[0], addr[1], addr[2], addr[3],
|
||||
addr[4], addr[5], addr[6], addr[7]);
|
||||
|
||||
snprintf(topic, sizeof(topic), "homie/%s/%s/$name", node_id, sensor_name);
|
||||
char display_name[48];
|
||||
snprintf(display_name, sizeof(display_name),
|
||||
"Temperature Sensor %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
addr[0], addr[1], addr[2], addr[3],
|
||||
addr[4], addr[5], addr[6], addr[7]);
|
||||
publish_retained(client, topic, display_name);
|
||||
|
||||
snprintf(topic, sizeof(topic), "homie/%s/%s/$properties", node_id, sensor_name);
|
||||
publish_retained(client, topic, "temperature,address,status,error_count");
|
||||
|
||||
// temperature properties
|
||||
snprintf(topic, sizeof(topic), "homie/%s/%s/temperature/$name", node_id, sensor_name);
|
||||
publish_retained(client, topic, "Temperature");
|
||||
snprintf(topic, sizeof(topic), "homie/%s/%s/temperature/$datatype", node_id, sensor_name);
|
||||
publish_retained(client, topic, "float");
|
||||
snprintf(topic, sizeof(topic), "homie/%s/%s/temperature/$unit", node_id, sensor_name);
|
||||
publish_retained(client, topic, "°C");
|
||||
|
||||
// address properties
|
||||
snprintf(topic, sizeof(topic), "homie/%s/%s/address/$name", node_id, sensor_name);
|
||||
publish_retained(client, topic, "ROM Address");
|
||||
snprintf(topic, sizeof(topic), "homie/%s/%s/address/$datatype", node_id, sensor_name);
|
||||
publish_retained(client, topic, "string");
|
||||
|
||||
char addr_str[24];
|
||||
snprintf(addr_str, sizeof(addr_str),
|
||||
"%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
addr[0], addr[1], addr[2], addr[3],
|
||||
addr[4], addr[5], addr[6], addr[7]);
|
||||
snprintf(topic, sizeof(topic), "homie/%s/%s/address", node_id, sensor_name);
|
||||
publish_retained(client, topic, addr_str);
|
||||
|
||||
snprintf(topic, sizeof(topic), "homie/%s/%s/status/$name", node_id, sensor_name);
|
||||
publish_retained(client, topic, "Sensor Status");
|
||||
snprintf(topic, sizeof(topic), "homie/%s/%s/status/$datatype", node_id, sensor_name);
|
||||
publish_retained(client, topic, "enum");
|
||||
snprintf(topic, sizeof(topic), "homie/%s/%s/status/$format", node_id, sensor_name);
|
||||
publish_retained(client, topic, "valid,invalid");
|
||||
|
||||
snprintf(topic, sizeof(topic), "homie/%s/%s/error_count/$name", node_id, sensor_name);
|
||||
publish_retained(client, topic, "Error Count");
|
||||
snprintf(topic, sizeof(topic), "homie/%s/%s/error_count/$datatype", node_id, sensor_name);
|
||||
publish_retained(client, topic, "integer");
|
||||
}
|
||||
}
|
||||
|
||||
// MQTT
|
||||
void onewire_temp_publish_values(MQTTClient* client, const char* node_id) {
|
||||
char topic[MAX_TOPIC_LENGTH];
|
||||
char value[8];
|
||||
uint8_t sensor_count = onewire_temp_count();
|
||||
|
||||
for (uint8_t i = 0; i < sensor_count; i++) {
|
||||
bool is_valid = onewire_temp_valid(i);
|
||||
const uint8_t* addr = onewire_temp_address(i);
|
||||
|
||||
char base_topic[MAX_TOPIC_LENGTH];
|
||||
snprintf(base_topic, sizeof(base_topic),
|
||||
"homie/%s/temp_%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
node_id, addr[0], addr[1], addr[2], addr[3],
|
||||
addr[4], addr[5], addr[6], addr[7]);
|
||||
|
||||
// publish status
|
||||
snprintf(topic, sizeof(topic), "%s/status", base_topic);
|
||||
publish_message(client, is_valid ? "valid" : "invalid", topic);
|
||||
|
||||
// publish error cnt
|
||||
snprintf(topic, sizeof(topic), "%s/error_count", base_topic);
|
||||
snprintf(value, sizeof(value), "%u", ow_sys.sensors[i].error_count);
|
||||
publish_message(client, value, topic);
|
||||
|
||||
snprintf(topic, sizeof(topic), "%s/temperature", base_topic);
|
||||
|
||||
if (is_valid) {
|
||||
float temp = onewire_temp_get(i);
|
||||
if (temp == ONEWIRE_TEMP_INVALID) {
|
||||
publish_message(client, "0.00", topic);
|
||||
} else {
|
||||
// temp to str
|
||||
int16_t temp_fixed = (int16_t)(temp * 100);
|
||||
uint8_t neg = temp_fixed < 0;
|
||||
if (neg) temp_fixed = -temp_fixed;
|
||||
|
||||
uint8_t idx = 0;
|
||||
if (neg) value[idx++] = '-';
|
||||
|
||||
uint16_t whole = temp_fixed / 100;
|
||||
uint8_t decimal = temp_fixed % 100;
|
||||
|
||||
if (whole >= 10) value[idx++] = '0' + (whole / 10);
|
||||
value[idx++] = '0' + (whole % 10);
|
||||
value[idx++] = '.';
|
||||
value[idx++] = '0' + (decimal / 10);
|
||||
value[idx++] = '0' + (decimal % 10);
|
||||
value[idx] = '\0';
|
||||
|
||||
publish_message(client, value, topic);
|
||||
}
|
||||
} else {
|
||||
publish_message(client, "0.00", topic);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user