Add configurable DS18B20 temperature probe support
This commit is contained in:
@@ -474,9 +474,9 @@ void buildStatusDocument(JsonDocument& doc) {
|
||||
temp["id"] = appConfig.tempSensors[i].id;
|
||||
temp["name"] = appConfig.tempSensors[i].name;
|
||||
temp["enabled"] = appConfig.tempSensors[i].enabled;
|
||||
temp["online"] = tempOnline[i];
|
||||
if (tempOnline[i]) {
|
||||
temp["temperature_f"] = tempValues[i];
|
||||
temp["online"] = sensors.online[i];
|
||||
if (sensors.online[i]) {
|
||||
temp["temperature_f"] = sensors.tempsF[i];
|
||||
} else {
|
||||
temp["temperature_f"] = nullptr;
|
||||
}
|
||||
@@ -912,6 +912,82 @@ void handleUartMessage(const String& line) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(type, "scan_temps") == 0) {
|
||||
scanTempSensors();
|
||||
|
||||
DynamicJsonDocument response(2048);
|
||||
response["type"] = "temp_scan_response";
|
||||
response["ok"] = true;
|
||||
|
||||
JsonArray devices = response.createNestedArray("devices");
|
||||
|
||||
int count = getTempScanResultCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
JsonObject device = devices.createNestedObject();
|
||||
device["index"] = i + 1;
|
||||
device["address"] = getTempScanResultAddress(i);
|
||||
}
|
||||
|
||||
serializeJson(response, DashboardSerial);
|
||||
DashboardSerial.println();
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(type, "assign_temp") == 0) {
|
||||
String id = doc["id"] | "";
|
||||
int slot = doc["slot"] | 0;
|
||||
int index = doc["index"] | 0;
|
||||
|
||||
int configIndex = -1;
|
||||
|
||||
if (id.length() > 0) {
|
||||
configIndex = findTempConfigIndexForUart(id);
|
||||
} else if (slot >= 1 && slot <= MAX_TEMP_SENSORS) {
|
||||
configIndex = slot - 1;
|
||||
}
|
||||
|
||||
if (configIndex < 0) {
|
||||
sendError(DashboardSerial, "unknown_temp_sensor");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!assignTempSensorByIndex(configIndex, index - 1)) {
|
||||
sendError(DashboardSerial, "invalid_temp_selection");
|
||||
return;
|
||||
}
|
||||
|
||||
saveConfig();
|
||||
sendConfigResponse(DashboardSerial);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(type, "clear_temp") == 0) {
|
||||
String id = doc["id"] | "";
|
||||
int slot = doc["slot"] | 0;
|
||||
|
||||
int configIndex = -1;
|
||||
|
||||
if (id.length() > 0) {
|
||||
configIndex = findTempConfigIndexForUart(id);
|
||||
} else if (slot >= 1 && slot <= MAX_TEMP_SENSORS) {
|
||||
configIndex = slot - 1;
|
||||
}
|
||||
|
||||
if (configIndex < 0) {
|
||||
sendError(DashboardSerial, "unknown_temp_sensor");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!clearTempSensor(configIndex)) {
|
||||
sendError(DashboardSerial, "unknown_temp_sensor");
|
||||
return;
|
||||
}
|
||||
|
||||
saveConfig();
|
||||
sendConfigResponse(DashboardSerial);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(type, "save_config") == 0) {
|
||||
saveConfig();
|
||||
sendConfigResponse(DashboardSerial);
|
||||
@@ -1191,6 +1267,47 @@ void handleDebugSerial() {
|
||||
}
|
||||
}
|
||||
|
||||
if (command == "scan temps") {
|
||||
scanTempSensors();
|
||||
printSensorAddresses();
|
||||
return;
|
||||
}
|
||||
|
||||
if (command.startsWith("assign temp ")) {
|
||||
String rest = command.substring(12);
|
||||
int space = rest.indexOf(' ');
|
||||
|
||||
if (space < 0) {
|
||||
Serial.println("Invalid command. Use: assign temp <slot> <number>");
|
||||
return;
|
||||
}
|
||||
|
||||
int slot = rest.substring(0, space).toInt();
|
||||
int index = rest.substring(space + 1).toInt();
|
||||
|
||||
if (!assignTempSensorByIndex(slot - 1, index - 1)) {
|
||||
Serial.println("Invalid temp slot or sensor number.");
|
||||
return;
|
||||
}
|
||||
|
||||
saveConfig();
|
||||
Serial.println("OK temp sensor assigned");
|
||||
return;
|
||||
}
|
||||
|
||||
if (command.startsWith("clear temp ")) {
|
||||
int slot = command.substring(11).toInt();
|
||||
|
||||
if (!clearTempSensor(slot - 1)) {
|
||||
Serial.println("Invalid temp slot.");
|
||||
return;
|
||||
}
|
||||
|
||||
saveConfig();
|
||||
Serial.println("OK temp sensor cleared");
|
||||
return;
|
||||
}
|
||||
|
||||
if (command.startsWith("tempname ")) {
|
||||
int firstSpace = command.indexOf(' ');
|
||||
int secondSpace = command.indexOf(' ', firstSpace + 1);
|
||||
@@ -1524,6 +1641,102 @@ void handleWifiClear() {
|
||||
sendWifiConfigJson();
|
||||
}
|
||||
|
||||
|
||||
void sendTempScanJson() {
|
||||
DynamicJsonDocument doc(2048);
|
||||
|
||||
doc["type"] = "temp_scan_response";
|
||||
doc["ok"] = true;
|
||||
|
||||
JsonArray devices = doc.createNestedArray("devices");
|
||||
|
||||
int count = getTempScanResultCount();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
JsonObject device = devices.createNestedObject();
|
||||
device["index"] = i + 1;
|
||||
device["address"] = getTempScanResultAddress(i);
|
||||
}
|
||||
|
||||
String output;
|
||||
serializeJson(doc, output);
|
||||
server.send(200, "application/json", output);
|
||||
}
|
||||
|
||||
void handleTempScan() {
|
||||
scanTempSensors();
|
||||
sendTempScanJson();
|
||||
}
|
||||
|
||||
void handleTempAssign() {
|
||||
DynamicJsonDocument doc(512);
|
||||
DeserializationError error = deserializeJson(doc, server.arg("plain"));
|
||||
|
||||
if (error) {
|
||||
server.send(400, "application/json", "{\"ok\":false,\"error\":\"invalid_json\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
String id = doc["id"] | "";
|
||||
int slot = doc["slot"] | 0;
|
||||
int index = doc["index"] | 0;
|
||||
|
||||
int configIndex = -1;
|
||||
|
||||
if (id.length() > 0) {
|
||||
configIndex = findTempConfigIndexForUart(id);
|
||||
} else if (slot >= 1 && slot <= MAX_TEMP_SENSORS) {
|
||||
configIndex = slot - 1;
|
||||
}
|
||||
|
||||
if (configIndex < 0) {
|
||||
server.send(400, "application/json", "{\"ok\":false,\"error\":\"unknown_temp_sensor\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!assignTempSensorByIndex(configIndex, index - 1)) {
|
||||
server.send(400, "application/json", "{\"ok\":false,\"error\":\"invalid_temp_selection\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
saveConfig();
|
||||
sendConfigJson();
|
||||
}
|
||||
|
||||
void handleTempClear() {
|
||||
DynamicJsonDocument doc(512);
|
||||
DeserializationError error = deserializeJson(doc, server.arg("plain"));
|
||||
|
||||
if (error) {
|
||||
server.send(400, "application/json", "{\"ok\":false,\"error\":\"invalid_json\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
String id = doc["id"] | "";
|
||||
int slot = doc["slot"] | 0;
|
||||
|
||||
int configIndex = -1;
|
||||
|
||||
if (id.length() > 0) {
|
||||
configIndex = findTempConfigIndexForUart(id);
|
||||
} else if (slot >= 1 && slot <= MAX_TEMP_SENSORS) {
|
||||
configIndex = slot - 1;
|
||||
}
|
||||
|
||||
if (configIndex < 0) {
|
||||
server.send(400, "application/json", "{\"ok\":false,\"error\":\"unknown_temp_sensor\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!clearTempSensor(configIndex)) {
|
||||
server.send(400, "application/json", "{\"ok\":false,\"error\":\"unknown_temp_sensor\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
saveConfig();
|
||||
sendConfigJson();
|
||||
}
|
||||
|
||||
void handleSaveConfig() {
|
||||
saveConfig();
|
||||
sendConfigJson();
|
||||
|
||||
@@ -4,13 +4,15 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "sensors.h"
|
||||
#include "app_config.h"
|
||||
|
||||
SensorData sensors;
|
||||
|
||||
OneWire oneWire(ONEWIRE_PIN);
|
||||
DallasTemperature ds18b20(&oneWire);
|
||||
|
||||
DeviceAddress sensorAddresses[4];
|
||||
DeviceAddress sensorAddresses[MAX_TEMP_SENSORS];
|
||||
String sensorAddressStrings[MAX_TEMP_SENSORS];
|
||||
int sensorCount = 0;
|
||||
|
||||
float cToF(float c) {
|
||||
@@ -21,67 +23,164 @@ bool validTempC(float tempC) {
|
||||
return tempC != DEVICE_DISCONNECTED_C && tempC > -55 && tempC < 125;
|
||||
}
|
||||
|
||||
void printAddress(DeviceAddress address) {
|
||||
String addressToString(DeviceAddress address) {
|
||||
String output = "";
|
||||
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
if (address[i] < 16) Serial.print("0");
|
||||
Serial.print(address[i], HEX);
|
||||
if (i < 7) Serial.print(":");
|
||||
if (address[i] < 16) output += "0";
|
||||
output += String(address[i], HEX);
|
||||
if (i < 7) output += ":";
|
||||
}
|
||||
|
||||
output.toUpperCase();
|
||||
return output;
|
||||
}
|
||||
|
||||
void printAddress(DeviceAddress address) {
|
||||
Serial.print(addressToString(address));
|
||||
}
|
||||
|
||||
bool addressMatches(DeviceAddress address, const String& expected) {
|
||||
if (expected.length() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String actual = addressToString(address);
|
||||
String normalizedExpected = expected;
|
||||
normalizedExpected.toUpperCase();
|
||||
|
||||
return actual == normalizedExpected;
|
||||
}
|
||||
|
||||
void clearSensorRuntimeData() {
|
||||
for (int i = 0; i < MAX_TEMP_SENSORS; i++) {
|
||||
sensors.tempsF[i] = -127.0;
|
||||
sensors.online[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
int scanTempSensors() {
|
||||
ds18b20.begin();
|
||||
|
||||
sensorCount = ds18b20.getDeviceCount();
|
||||
|
||||
if (sensorCount > MAX_TEMP_SENSORS) {
|
||||
sensorCount = MAX_TEMP_SENSORS;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_TEMP_SENSORS; i++) {
|
||||
sensorAddressStrings[i] = "";
|
||||
}
|
||||
|
||||
for (int i = 0; i < sensorCount; i++) {
|
||||
if (ds18b20.getAddress(sensorAddresses[i], i)) {
|
||||
sensorAddressStrings[i] = addressToString(sensorAddresses[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return sensorCount;
|
||||
}
|
||||
|
||||
int getTempScanResultCount() {
|
||||
return sensorCount;
|
||||
}
|
||||
|
||||
String getTempScanResultAddress(int index) {
|
||||
if (index < 0 || index >= sensorCount) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return sensorAddressStrings[index];
|
||||
}
|
||||
|
||||
void printSensorAddresses() {
|
||||
Serial.println("DS18B20 Sensors Found:");
|
||||
|
||||
for (int i = 0; i < sensorCount; i++) {
|
||||
Serial.print("Sensor ");
|
||||
Serial.print(i);
|
||||
Serial.print(": ");
|
||||
printAddress(sensorAddresses[i]);
|
||||
Serial.println();
|
||||
Serial.print(i + 1);
|
||||
Serial.print(") ");
|
||||
Serial.println(sensorAddressStrings[i]);
|
||||
}
|
||||
|
||||
if (sensorCount == 0) {
|
||||
Serial.println("No DS18B20 sensors found.");
|
||||
} else {
|
||||
Serial.println("Use: assign temp <slot> <number>");
|
||||
}
|
||||
}
|
||||
|
||||
void initSensors() {
|
||||
ds18b20.begin();
|
||||
sensorCount = ds18b20.getDeviceCount();
|
||||
|
||||
if (sensorCount > 4) {
|
||||
sensorCount = 4;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sensorCount; i++) {
|
||||
ds18b20.getAddress(sensorAddresses[i], i);
|
||||
}
|
||||
|
||||
clearSensorRuntimeData();
|
||||
scanTempSensors();
|
||||
printSensorAddresses();
|
||||
}
|
||||
|
||||
void updateSensors() {
|
||||
clearSensorRuntimeData();
|
||||
|
||||
ds18b20.requestTemperatures();
|
||||
|
||||
float tempsF[4] = {-127, -127, -127, -127};
|
||||
bool online[4] = {false, false, false, false};
|
||||
for (int configIndex = 0; configIndex < MAX_TEMP_SENSORS; configIndex++) {
|
||||
if (!appConfig.tempSensors[configIndex].enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sensorCount; i++) {
|
||||
float tempC = ds18b20.getTempC(sensorAddresses[i]);
|
||||
String configuredAddress = appConfig.tempSensors[configIndex].address;
|
||||
|
||||
if (validTempC(tempC)) {
|
||||
tempsF[i] = cToF(tempC);
|
||||
online[i] = true;
|
||||
if (configuredAddress.length() == 0) {
|
||||
// Backward-compatible behavior:
|
||||
// if no address is assigned, use physical scan order.
|
||||
if (configIndex < sensorCount) {
|
||||
float tempC = ds18b20.getTempC(sensorAddresses[configIndex]);
|
||||
|
||||
if (validTempC(tempC)) {
|
||||
sensors.tempsF[configIndex] = cToF(tempC);
|
||||
sensors.online[configIndex] = true;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int physicalIndex = 0; physicalIndex < sensorCount; physicalIndex++) {
|
||||
if (!addressMatches(sensorAddresses[physicalIndex], configuredAddress)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float tempC = ds18b20.getTempC(sensorAddresses[physicalIndex]);
|
||||
|
||||
if (validTempC(tempC)) {
|
||||
sensors.tempsF[configIndex] = cToF(tempC);
|
||||
sensors.online[configIndex] = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sensors.temp1 = tempsF[0];
|
||||
sensors.temp2 = tempsF[1];
|
||||
sensors.temp3 = tempsF[2];
|
||||
sensors.temp4 = tempsF[3];
|
||||
bool assignTempSensorByIndex(int configIndex, int scanIndex) {
|
||||
if (configIndex < 0 || configIndex >= MAX_TEMP_SENSORS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sensors.temp1Online = online[0];
|
||||
sensors.temp2Online = online[1];
|
||||
sensors.temp3Online = online[2];
|
||||
sensors.temp4Online = online[3];
|
||||
if (scanIndex < 0 || scanIndex >= sensorCount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
appConfig.tempSensors[configIndex].address = sensorAddressStrings[scanIndex];
|
||||
appConfig.tempSensors[configIndex].enabled = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool clearTempSensor(int configIndex) {
|
||||
if (configIndex < 0 || configIndex >= MAX_TEMP_SENSORS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
appConfig.tempSensors[configIndex].address = "";
|
||||
appConfig.tempSensors[configIndex].enabled = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
struct SensorData {
|
||||
float temp1 = -127.0;
|
||||
float temp2 = -127.0;
|
||||
float temp3 = -127.0;
|
||||
float temp4 = -127.0;
|
||||
#include <Arduino.h>
|
||||
#include "app_config.h"
|
||||
|
||||
bool temp1Online = false;
|
||||
bool temp2Online = false;
|
||||
bool temp3Online = false;
|
||||
bool temp4Online = false;
|
||||
struct SensorData {
|
||||
float tempsF[MAX_TEMP_SENSORS];
|
||||
bool online[MAX_TEMP_SENSORS];
|
||||
};
|
||||
|
||||
extern SensorData sensors;
|
||||
|
||||
void initSensors();
|
||||
void updateSensors();
|
||||
|
||||
int scanTempSensors();
|
||||
int getTempScanResultCount();
|
||||
String getTempScanResultAddress(int index);
|
||||
void printSensorAddresses();
|
||||
|
||||
bool assignTempSensorByIndex(int configIndex, int scanIndex);
|
||||
bool clearTempSensor(int configIndex);
|
||||
|
||||
Reference in New Issue
Block a user