All features working

This commit is contained in:
Christoph Hagen 2023-06-01 16:18:48 +02:00
parent e1852d2989
commit a7a8367687
8 changed files with 206 additions and 153 deletions

View File

@ -5,7 +5,10 @@
constexpr uint32_t serialBaudRate = 115200; constexpr uint32_t serialBaudRate = 115200;
constexpr gpio_num_t wakeupButtonPin = GPIO_NUM_13; // The pin connected to the push button
// The button should be connected to GND
constexpr gpio_num_t wakeupButtonPin = GPIO_NUM_27;
// The time (in seconds) for which the device should stay awake after the button is pressed // The time (in seconds) for which the device should stay awake after the button is pressed
// The device also stays awake as long as a bluetooth connection is active // The device also stays awake as long as a bluetooth connection is active
constexpr uint32_t wakeupDurationAfterButtonPress = 30; constexpr uint32_t wakeupDurationAfterButtonPress = 30;

View File

@ -40,6 +40,10 @@ void saveTemperatureAtCurrentIndex(Temperature temp);
uint16_t getTotalNumberOfStoredBytes(); uint16_t getTotalNumberOfStoredBytes();
uint16_t getNumberOfMeasurements();
uint8_t getLastTemperature(uint8_t sensorIndex);
uint16_t getRecordedBytesAtOffset(uint8_t* buffer, uint16_t offset, uint16_t count); uint16_t getRecordedBytesAtOffset(uint8_t* buffer, uint16_t offset, uint16_t count);
void discardAllRecordedBytes(); void discardAllRecordedBytes();

View File

@ -2,8 +2,15 @@
#include <stdint.h> #include <stdint.h>
// Note: Pin requires external 4.7kOhm pull-up
constexpr uint8_t TEMPERATURE_SENSOR_PIN = 23;
constexpr uint8_t TEMPERATURE_SENSOR_MAX_COUNT = 2; constexpr uint8_t TEMPERATURE_SENSOR_MAX_COUNT = 2;
// The number of bytes composing a temperature sensor address
constexpr int TEMPERATURE_SENSOR_ADDRESS_SIZE = 8;
constexpr uint8_t temperatureSensorNotAvailable = 0; constexpr uint8_t temperatureSensorNotAvailable = 0;
constexpr uint8_t temperatureSensorFailure = 1; constexpr uint8_t temperatureSensorFailure = 1;
constexpr uint8_t temperatureMinimumValue = 2; constexpr uint8_t temperatureMinimumValue = 2;
@ -32,3 +39,5 @@ struct Temperature {
void temperatureConfigure(); void temperatureConfigure();
void temperaturePerformUpdate(Temperature* temperatures); void temperaturePerformUpdate(Temperature* temperatures);
void copySensorAddress(uint8_t index, uint8_t* buffer);

View File

@ -15,5 +15,3 @@ framework = arduino
lib_deps = lib_deps =
pstolarz/OneWireNg @ ^0.11.2 pstolarz/OneWireNg @ ^0.11.2
monitor_speed = 115200 monitor_speed = 115200
monitor_port = /dev/tty.usbserial-0001
upload_port = /dev/tty.usbserial-0001

View File

@ -9,6 +9,7 @@
#include "bluetooth.h" #include "bluetooth.h"
#include "storage.h" #include "storage.h"
#include "config.h" #include "config.h"
#include "temperature.h"
constexpr size_t bluetoothMaxDataSize = 200; constexpr size_t bluetoothMaxDataSize = 200;
@ -17,10 +18,10 @@ constexpr uint16_t DEVINFO_MANUFACTURER_UUID = 0x2a29;
constexpr uint16_t DEVINFO_NAME_UUID = 0x2a24; constexpr uint16_t DEVINFO_NAME_UUID = 0x2a24;
constexpr uint16_t DEVINFO_SERIAL_UUID = 0x2a25; constexpr uint16_t DEVINFO_SERIAL_UUID = 0x2a25;
const char* deviceName = "Window"; const char* deviceName = "TempTrack";
const char* manufacturerName = "CH"; const char* manufacturerName = "CH";
const char* serviceUUID = "22071991-feed-deaf-babe-150420870001"; const char* serviceUUID = "22071991-cccc-cccc-cccc-000000000001";
const char* characteristicUUID = "22071991-feed-deaf-babe-150420870002"; const char* characteristicUUID = "22071991-cccc-cccc-cccc-000000000002";
bool isConnected = false; bool isConnected = false;
uint8_t bluetoothOutgoingBuffer[bluetoothMaxDataSize + 1]; uint8_t bluetoothOutgoingBuffer[bluetoothMaxDataSize + 1];
@ -67,7 +68,14 @@ BLE2902 descriptor{};
BLEServer *server; BLEServer *server;
Receiver receiver{}; Receiver receiver{};
bool bluetoothIsConfigured = false;
void bluetoothConfigure() { void bluetoothConfigure() {
if (bluetoothIsConfigured) {
return;
}
bluetoothIsConfigured = true;
bluetoothDataBuffer = bluetoothOutgoingBuffer + 1; bluetoothDataBuffer = bluetoothOutgoingBuffer + 1;
bluetoothResponse = bluetoothOutgoingBuffer; bluetoothResponse = bluetoothOutgoingBuffer;
@ -98,6 +106,8 @@ void bluetoothConfigure() {
characteristic->setValue(chipId); characteristic->setValue(chipId);
service->start(); service->start();
bluetoothStartAdvertising();
} }
void bluetoothStartAdvertising() { void bluetoothStartAdvertising() {
@ -123,9 +133,14 @@ enum class BluetoothRequest: uint8_t {
* - No additional bytes expected * - No additional bytes expected
* *
* Response: * Response:
* - BluetoothResponse::success, plus the number of bytes as a uint16_t (2 bytes) * - BluetoothResponse::success
* - the number of bytes as a uint16_t (2 bytes)
* - the number of seconds until the next measurement as a uint16_t (2 bytes)
* - the number of seconds between measurements as a uint16_t (2 bytes)
* - the number of measurements as a uint16_t (2 bytes)
* - the number of seconds since power on as a uint32_t (4 bytes)
*/ */
getNumberOfRecordedBytes = 0, getInfo = 0,
/** /**
* @brief Request recording data * @brief Request recording data
@ -152,53 +167,14 @@ enum class BluetoothRequest: uint8_t {
* This may happen when a new temperature recording is performed in between calls * This may happen when a new temperature recording is performed in between calls
*/ */
clearRecordingBuffer = 2, clearRecordingBuffer = 2,
/**
* @brief Request the time since the device was turned on
*
* Request:
* - No additional bytes expected
*
* Response:
* - BluetoothResponse::success, plus the number of seconds as a uint32_t (4 bytes)
*/
getCurrentTime = 3,
/**
* @brief Request the number of seconds until the next measurement is performed
*
* Request:
* - No additional bytes expected
*
* Response:
* - BluetoothResponse::success, plus the number of seconds as a uint16_t (2 bytes)
*/
getSecondsUntilNextMeasurement = 4,
/**
* @brief Get the number of seconds
*
* Request:
* - No additional bytes expected
*
* Response:
* - BluetoothResponse::success, plus the number of seconds as a uint16_t (2 bytes)
*/
getMeasurementInterval = 5,
}; };
enum class BluetoothResponse: uint8_t { enum class BluetoothResponse: uint8_t {
/** /** The response to the last request is provided */
* @brief The response to the last request is provided
*
*/
success = 0, success = 0,
/** /** Invalid command received */
* @brief Invalid command received
*
*/
invalidCommand = 1, invalidCommand = 1,
responseTooLarge = 2, responseTooLarge = 2,
@ -245,17 +221,59 @@ void bluetoothDidReceiveData(uint8_t* buffer, size_t count) {
return; return;
} }
uint16_t offset; uint32_t currentTime;
uint16_t value;
BluetoothRequest request = static_cast<BluetoothRequest>(buffer[0]); BluetoothRequest request = static_cast<BluetoothRequest>(buffer[0]);
switch (request) switch (request) {
{ case BluetoothRequest::getInfo:
case BluetoothRequest::getNumberOfRecordedBytes: // BluetoothResponse::success
count = getTotalNumberOfStoredBytes(); setResponse(BluetoothResponse::success);
setSuccessResponseWithNumber(count);
// the number of bytes as a uint16_t (2 bytes)
value = getTotalNumberOfStoredBytes();
memcpy(bluetoothDataBuffer, &value, sizeof(uint16_t));
bluetoothDataCount = sizeof(uint16_t);
// the number of seconds until the next measurement as a uint16_t (2 bytes)
value = secondsUntilNextTemperatureMeasurement();
memcpy(bluetoothDataBuffer + bluetoothDataCount, &value, sizeof(uint16_t));
bluetoothDataCount += sizeof(uint16_t);
// the number of seconds between measurements as a uint16_t (2 bytes)
value = temperatureMeasurementIntervalSeconds;
memcpy(bluetoothDataBuffer + bluetoothDataCount, &value, sizeof(uint16_t));
bluetoothDataCount += sizeof(uint16_t);
// the number of measurements as a uint16_t (2 bytes)
value = getNumberOfMeasurements();
memcpy(bluetoothDataBuffer + bluetoothDataCount, &value, sizeof(uint16_t));
bluetoothDataCount += sizeof(uint16_t);
// the maximum number of bytes that can be copied
value = bluetoothMaxDataSize;
memcpy(bluetoothDataBuffer + bluetoothDataCount, &value, sizeof(uint16_t));
bluetoothDataCount += sizeof(uint16_t);
// the number of seconds since power on as a uint32_t (4 bytes)
currentTime = time(NULL);
memcpy(bluetoothDataBuffer + bluetoothDataCount, &currentTime, sizeof(uint32_t));
bluetoothDataCount += sizeof(uint32_t);
// The last temperatures
bluetoothDataBuffer[bluetoothDataCount] = getLastTemperature(0);
bluetoothDataCount += sizeof(uint8_t);
bluetoothDataBuffer[bluetoothDataCount] = getLastTemperature(1);
bluetoothDataCount += sizeof(uint8_t);
// Temperature sensor addresses
copySensorAddress(0, bluetoothDataBuffer + bluetoothDataCount);
bluetoothDataCount += TEMPERATURE_SENSOR_ADDRESS_SIZE;
copySensorAddress(1, bluetoothDataBuffer + bluetoothDataCount);
bluetoothDataCount += TEMPERATURE_SENSOR_ADDRESS_SIZE;
break; break;
case BluetoothRequest::clearRecordingBuffer: case BluetoothRequest::clearRecordingBuffer:
count = *((uint16_t*) buffer + 1); memcpy(&count, buffer + 1, sizeof(uint16_t));
if (count != getTotalNumberOfStoredBytes()) { if (count != getTotalNumberOfStoredBytes()) {
setResponseWithoutData(BluetoothResponse::invalidNumberOfBytesToDelete); setResponseWithoutData(BluetoothResponse::invalidNumberOfBytesToDelete);
} else { } else {
@ -265,33 +283,20 @@ void bluetoothDidReceiveData(uint8_t* buffer, size_t count) {
break; break;
case BluetoothRequest::getRecordingData: case BluetoothRequest::getRecordingData:
if (count != 5) { if (count != sizeof(uint16_t) + sizeof(uint8_t)) {
setResponseWithoutData(BluetoothResponse::invalidCommand); setResponseWithoutData(BluetoothResponse::invalidCommand);
break; break;
} }
offset = *((uint16_t*) buffer + 1); memcpy(&value, buffer + sizeof(uint8_t) , sizeof(uint16_t));
count = *((uint16_t*) buffer + 3); memcpy(&count, buffer + sizeof(uint8_t) + sizeof(uint16_t), sizeof(uint16_t));
if (count > bluetoothMaxDataSize) { if (count > bluetoothMaxDataSize) {
setResponseWithoutData(BluetoothResponse::responseTooLarge); setResponseWithoutData(BluetoothResponse::responseTooLarge);
break; break;
} }
count = getRecordedBytesAtOffset(bluetoothDataBuffer, offset, count); count = getRecordedBytesAtOffset(bluetoothDataBuffer, value, count);
bluetoothDataCount = count; bluetoothDataCount = count;
break; break;
case BluetoothRequest::getCurrentTime:
setSuccessResponseWithUInt32(time(NULL));
break;
case BluetoothRequest::getSecondsUntilNextMeasurement:
count = secondsUntilNextTemperatureMeasurement();
setSuccessResponseWithNumber(count);
break;
case BluetoothRequest::getMeasurementInterval:
setSuccessResponseWithNumber(temperatureMeasurementIntervalSeconds);
break;
default: default:
setResponseWithoutData(BluetoothResponse::unknownCommand); setResponseWithoutData(BluetoothResponse::unknownCommand);
break; break;

View File

@ -7,8 +7,6 @@
#include "storage.h" #include "storage.h"
#include "temperature.h" #include "temperature.h"
Temperature samples[temperatureSensorCount]; Temperature samples[temperatureSensorCount];
// Indicate when the next temperature measurement should be performed // Indicate when the next temperature measurement should be performed
@ -71,7 +69,7 @@ void deepSleepUntilNextTemperatureMeasurement() {
* @return false The button is not pressed * @return false The button is not pressed
*/ */
bool wakeupButtonIsPressed() { bool wakeupButtonIsPressed() {
return gpio_get_level(wakeupButtonPin) == 1; return gpio_get_level(wakeupButtonPin) == 0;
} }
void updateStayAwakeTime() { void updateStayAwakeTime() {
@ -85,33 +83,38 @@ bool shouldStayAwakeDueToActivity() {
return bluetoothIsConnected(); return bluetoothIsConnected();
} }
void setup() { void enableLED() {
// Configure LED pin // Configure LED pin
// Equivalent to: // Equivalent to: pinMode(1, OUTPUT);
// pinMode(1, OUTPUT);
gpio_config_t ledConfig; gpio_config_t ledConfig;
ledConfig.pin_bit_mask = (1ULL << 1); ledConfig.pin_bit_mask = (1ULL << 1);
ledConfig.mode = GPIO_MODE_OUTPUT; ledConfig.mode = GPIO_MODE_OUTPUT;
ledConfig.pull_down_en = GPIO_PULLDOWN_ENABLE; gpio_config(&ledConfig);
//gpio_config(&ledConfig); // TODO: Enable LED
// Enable LED, as long as ESP is awake // Enable LED, as long as ESP is awake
// Equivalent to: // Equivalent to: digitalWrite(1, LOW);
// digitalWrite(1, HIGH); gpio_set_level(GPIO_NUM_1, 0); // For this led, low means on
//gpio_set_level(GPIO_NUM_1, 1); }
// Configure button pin to wake up ESP from deep sleep on high signal with pulldown void setup() {
// GPIO13 -> RTC_GPIO14 //Serial.begin(serialBaudRate);
rtc_gpio_pulldown_en(wakeupButtonPin);
rtc_gpio_wakeup_enable(wakeupButtonPin, GPIO_INTR_HIGH_LEVEL); // LED useless inside case
//enableLED();
// Configure button pin to wake up ESP from deep sleep on low signal with pullup
rtc_gpio_pullup_en(wakeupButtonPin);
esp_sleep_enable_ext0_wakeup(wakeupButtonPin, 0);
// Enable EEPROM to persist measurements // Enable EEPROM to persist measurements
// Only needed if sufficient measurements are in RTC memory // Only needed if sufficient measurements are in RTC memory
storageConfigure(); storageConfigure();
if (wakeupButtonIsPressed()) { // Configure bluetooth if wake button was pressed
if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_EXT0) {
Serial.println("Wake after button press");
bluetoothConfigure(); bluetoothConfigure();
// Serial.println("Bluetooth configured"); updateStayAwakeTime();
} }
// Configure the temperature sensors // Configure the temperature sensors
@ -119,37 +122,29 @@ void setup() {
temperatureConfigure(); temperatureConfigure();
// TODO: Remove // TODO: Remove
Serial.begin(serialBaudRate);
Serial.println("Setup complete"); Serial.println("Setup complete");
} }
void loop() { void loop() {
if (shouldMeasureTemperature()) { if (shouldMeasureTemperature()) {
Serial.println("Measuring");
temperaturePerformUpdate(samples); temperaturePerformUpdate(samples);
saveTemperatures(samples); saveTemperatures(samples);
setNextTemperatureMeasurementInterval(); setNextTemperatureMeasurementInterval();
} }
if (wakeupButtonIsPressed()) { if (wakeupButtonIsPressed()) {
bluetoothConfigure(); // Only done once internally
updateStayAwakeTime(); updateStayAwakeTime();
} }
if (!shouldStayAwakeDueToActivity()) { if (!shouldStayAwakeDueToActivity()) {
Serial.print("Sleeping for ");
Serial.print(secondsUntilNextTemperatureMeasurement());
Serial.println(" seconds");
// May return, if less then one second to wait // May return, if less then one second to wait
// Otherwise control flow starts with setup() again // Otherwise control flow starts with setup() again
deepSleepUntilNextTemperatureMeasurement(); deepSleepUntilNextTemperatureMeasurement();
} }
} }
/*
255
0
0
255
0
0
*/

View File

@ -11,9 +11,11 @@ constexpr uint32_t eepromChunkSize = 100;
// Storage for temperature measurements in RTC memory that survives deep sleep // Storage for temperature measurements in RTC memory that survives deep sleep
RTC_DATA_ATTR uint8_t data[rtcStorageSize]; RTC_DATA_ATTR uint8_t data[rtcStorageSize];
RTC_DATA_ATTR uint16_t dataIndex = 0; RTC_DATA_ATTR uint16_t dataIndex = 0;
RTC_DATA_ATTR uint16_t numberOfMeasurements = 0;
// The index into EEPROM storage where the next data should be written // The index into EEPROM storage where the next data should be written
RTC_DATA_ATTR uint32_t eepromIndex = 0; RTC_DATA_ATTR uint32_t eepromIndex = 0;
RTC_DATA_ATTR bool isFirstRunAfterPowerOn = true;
// Keeps the last valid temperatures for each sensor // Keeps the last valid temperatures for each sensor
RTC_DATA_ATTR Temperature lastTemperatures[temperatureSensorCount]; RTC_DATA_ATTR Temperature lastTemperatures[temperatureSensorCount];
@ -21,7 +23,7 @@ RTC_DATA_ATTR Temperature lastTemperatures[temperatureSensorCount];
bool didSetupEEPROM = false; bool didSetupEEPROM = false;
// On first boot, this is set to true; Afterwards it's remembered to be false // On first boot, this is set to true; Afterwards it's remembered to be false
RTC_DATA_ATTR bool shouldStartNewRecording = true; RTC_DATA_ATTR bool eepromIsConsideredEmpty = true;
constexpr uint16_t eepromOffset = 2; // Size of uint16 constexpr uint16_t eepromOffset = 2; // Size of uint16
constexpr uint16_t eepromDataSize = eepromSize - eepromOffset; constexpr uint16_t eepromDataSize = eepromSize - eepromOffset;
@ -32,33 +34,36 @@ void setupEEPROMIfNeeded() {
} }
bool success = EEPROM.begin(eepromSize); bool success = EEPROM.begin(eepromSize);
if (!success) { if (!success) {
// Serial.println("Failed to set up EEPROM"); Serial.println("Failed to set up EEPROM");
didSetupEEPROM = false; didSetupEEPROM = false;
} }
// Serial.print("EEPROM Size "); Serial.print("EEPROM size: ");
// Serial.print(eepromSize); Serial.println(eepromSize);
// Serial.println(" bytes");
didSetupEEPROM = true; didSetupEEPROM = true;
} }
void storageConfigure() { void resetLastMeasurements() {
if (dataIndex >= eepromChunkSize) {
// Configure EEPROM at start
// May be initialized later
setupEEPROMIfNeeded();
}
// Ensure that first values are stored
for (uint8_t index = 0; index < temperatureSensorCount; index += 1) { for (uint8_t index = 0; index < temperatureSensorCount; index += 1) {
lastTemperatures[index].status == TemperatureStatus::sensorNotFound; lastTemperatures[index].status == TemperatureStatus::sensorNotFound;
lastTemperatures[index].value = 0;
} }
} }
uint16_t getNumberOfBytesStoredInEEPROM() { void storageConfigure() {
setupEEPROMIfNeeded(); if (!isFirstRunAfterPowerOn) {
if (shouldStartNewRecording) { return;
return 0; // Discard any
} }
isFirstRunAfterPowerOn = false;
// Ensure that first values are stored
resetLastMeasurements();
}
uint16_t getNumberOfBytesStoredInEEPROM() {
if (eepromIsConsideredEmpty) {
return 0; // Discard any previous bytes
}
setupEEPROMIfNeeded();
return EEPROM.readShort(0); return EEPROM.readShort(0);
} }
@ -71,7 +76,12 @@ void moveDataToEEPROMIfNeeded() {
if (eepromIndex >= eepromDataSize) { if (eepromIndex >= eepromDataSize) {
return; // No more space in EEPROM, keep filling RTC memory return; // No more space in EEPROM, keep filling RTC memory
} }
shouldStartNewRecording = false; // Preparing to write new data, so set to false
eepromIsConsideredEmpty = false;
setupEEPROMIfNeeded();
if (!didSetupEEPROM) {
return;
}
// Write until EEPROM is full // Write until EEPROM is full
uint16_t bytesRemaining = eepromDataSize - eepromIndex; uint16_t bytesRemaining = eepromDataSize - eepromIndex;
@ -89,7 +99,18 @@ void moveDataToEEPROMIfNeeded() {
void saveByteAtCurrentIndex(uint8_t byte) { void saveByteAtCurrentIndex(uint8_t byte) {
data[dataIndex] = byte; data[dataIndex] = byte;
dataIndex += 1; dataIndex += 1;
Serial.println(byte); }
uint8_t byteForAbsoluteTemperature(long temp) {
// Convert to temperature range
long converted = (temp - (temperatureShiftForStorage)) / 500;
if (converted < temperatureMinimumValue) {
return temperatureMinimumValue;
}
if (converted > temperatureMaximumValue) {
return temperatureMaximumValue;
}
return converted;
} }
void saveTemperatureAtCurrentIndex(Temperature temp) { void saveTemperatureAtCurrentIndex(Temperature temp) {
@ -97,15 +118,8 @@ void saveTemperatureAtCurrentIndex(Temperature temp) {
saveByteAtCurrentIndex(static_cast<uint8_t>(temp.status)); saveByteAtCurrentIndex(static_cast<uint8_t>(temp.status));
return; return;
} }
// Convert to temperature range uint8_t byte = byteForAbsoluteTemperature(temp.value);
long converted = (temp.value - (-40000)) / 500; saveByteAtCurrentIndex(byte);
if (converted < temperatureMinimumValue) {
saveByteAtCurrentIndex(temperatureMinimumValue);
} else if (converted > temperatureMaximumValue) {
saveByteAtCurrentIndex(temperatureMaximumValue);
} else {
saveByteAtCurrentIndex(converted);
}
} }
bool needsAbsoluteTemperatureRecording(Temperature* temperatures) { bool needsAbsoluteTemperatureRecording(Temperature* temperatures) {
@ -164,12 +178,24 @@ void saveTemperatures(Temperature* temperatures) {
} }
moveDataToEEPROMIfNeeded(); moveDataToEEPROMIfNeeded();
numberOfMeasurements += 1;
} }
uint16_t getTotalNumberOfStoredBytes() { uint16_t getTotalNumberOfStoredBytes() {
return getNumberOfBytesStoredInEEPROM() + dataIndex; return getNumberOfBytesStoredInEEPROM() + dataIndex;
} }
uint16_t getNumberOfMeasurements() {
return numberOfMeasurements;
}
uint8_t getLastTemperature(uint8_t sensorIndex) {
if (lastTemperatures[sensorIndex].status != TemperatureStatus::temperatureIsValid) {
return static_cast<uint8_t>(lastTemperatures[sensorIndex].status);
}
return byteForAbsoluteTemperature(lastTemperatures[sensorIndex].value);
}
uint16_t getRecordedBytesAtOffset(uint8_t* buffer, uint16_t offset, uint16_t count) { uint16_t getRecordedBytesAtOffset(uint8_t* buffer, uint16_t offset, uint16_t count) {
// TODO: Check limits // TODO: Check limits
uint16_t eepromByteCount = getNumberOfBytesStoredInEEPROM(); uint16_t eepromByteCount = getNumberOfBytesStoredInEEPROM();
@ -191,6 +217,9 @@ uint16_t getRecordedBytesAtOffset(uint8_t* buffer, uint16_t offset, uint16_t cou
} }
void discardAllRecordedBytes() { void discardAllRecordedBytes() {
shouldStartNewRecording = true; eepromIsConsideredEmpty = true;
dataIndex = 0; dataIndex = 0;
numberOfMeasurements = 0;
resetLastMeasurements();
} }

View File

@ -11,14 +11,9 @@ constexpr int8_t TEMPERATURE_ALARM_LIMIT_HIGH = 80;
#define INVALID_SENSOR_INDEX 255 #define INVALID_SENSOR_INDEX 255
constexpr uint8_t TEMPERATURE_SENSOR_ERROR_THRESHOLD = 3; constexpr uint8_t TEMPERATURE_SENSOR_ERROR_THRESHOLD = 3;
// The number of bytes composing a temperature sensor address
constexpr int TEMPERATURE_SENSOR_ADDRESS_SIZE = 8;
constexpr bool TEMPERATURE_SENSOR_PARASITE_POWER = false; constexpr bool TEMPERATURE_SENSOR_PARASITE_POWER = false;
// Note: Pin requires external 4.7kOhm pull-up
constexpr uint8_t TEMPERATURE_SENSOR_PIN = 13;
// Indicator if the temperature sensors have been configured // Indicator if the temperature sensors have been configured
RTC_DATA_ATTR bool didConfigureTemperatureSensors = false; RTC_DATA_ATTR bool didConfigureTemperatureSensors = false;
@ -67,7 +62,7 @@ uint8_t getSensorIndex(const OneWireNg::Id& id) {
uint8_t getIndexOfFirstEmptySensorSlot() { uint8_t getIndexOfFirstEmptySensorSlot() {
for (uint8_t sensorIndex = 0; sensorIndex < TEMPERATURE_SENSOR_MAX_COUNT; sensorIndex += 1) { for (uint8_t sensorIndex = 0; sensorIndex < TEMPERATURE_SENSOR_MAX_COUNT; sensorIndex += 1) {
if (!sensors[sensorIndex].isSet) { if (!sensors[sensorIndex].isSet) {
return false; return sensorIndex;
} }
} }
return INVALID_SENSOR_INDEX; return INVALID_SENSOR_INDEX;
@ -85,6 +80,7 @@ uint8_t addNewSensor(const OneWireNg::Id& id) {
sensors[sensorIndex].address[pos] = id[pos]; sensors[sensorIndex].address[pos] = id[pos];
} }
sensors[sensorIndex].isSet = true; sensors[sensorIndex].isSet = true;
sensors[sensorIndex].foundDuringCurrentUpdate = true;
availableSensorCount += 1; availableSensorCount += 1;
return sensorIndex; return sensorIndex;
} }
@ -94,6 +90,10 @@ void removeSensorAtIndex(uint8_t sensorIndex) {
availableSensorCount -= 1; availableSensorCount -= 1;
} }
void copySensorAddress(uint8_t index, uint8_t* buffer) {
memcpy(buffer, sensors[index].address, TEMPERATURE_SENSOR_ADDRESS_SIZE);
}
void printSensorAddress(const OneWireNg::Id& id) { void printSensorAddress(const OneWireNg::Id& id) {
for (uint8_t i = 0; i < TEMPERATURE_SENSOR_ADDRESS_SIZE; i += 1) { for (uint8_t i = 0; i < TEMPERATURE_SENSOR_ADDRESS_SIZE; i += 1) {
Serial.print(" 0x"); Serial.print(" 0x");
@ -124,15 +124,6 @@ void temperatureConfigure() {
scratchpad = reinterpret_cast<DSTherm::Scratchpad*>(&scratchpadBuffer[0]); scratchpad = reinterpret_cast<DSTherm::Scratchpad*>(&scratchpadBuffer[0]);
// Write sensor resolution and set limits
if (sensorInterface.writeScratchpadAll(
TEMPERATURE_ALARM_LIMIT_HIGH,
TEMPERATURE_ALARM_LIMIT_LOW,
TEMPERATURE_RESOLUTION) != OneWireNg::ErrorCode::EC_SUCCESS) {
Serial.println("Failed to set temperature limits and resolution");
return;
}
// Clear discovery flags // Clear discovery flags
clearFoundIndicatorForAllSensors(); clearFoundIndicatorForAllSensors();
@ -141,10 +132,10 @@ void temperatureConfigure() {
uint8_t sensorIndex = getSensorIndex(id); uint8_t sensorIndex = getSensorIndex(id);
if (sensorIndex == INVALID_SENSOR_INDEX) { if (sensorIndex == INVALID_SENSOR_INDEX) {
sensorIndex = addNewSensor(id); sensorIndex = addNewSensor(id);
Serial.print("Added sensor "); Serial.print("Sensor ");
Serial.print(sensorIndex);
Serial.print(": ");
printSensorAddress(id); printSensorAddress(id);
Serial.print(" at index ");
Serial.println(sensorIndex);
continue; continue;
} }
// Mark existing sensor // Mark existing sensor
@ -165,11 +156,26 @@ void temperatureConfigure() {
} }
Serial.print("Removed sensor "); Serial.print("Removed sensor ");
printSensorAddressAtIndex(sensorIndex); printSensorAddressAtIndex(sensorIndex);
Serial.print(" at index ");
Serial.println(sensorIndex); Serial.println(sensorIndex);
removeSensorAtIndex(sensorIndex); removeSensorAtIndex(sensorIndex);
} }
if (availableSensorCount == 0) {
Serial.println("No sensors available");
return;
}
Serial.print(availableSensorCount);
Serial.println(" temperature sensors available");
// Write sensor resolution and set limits
if (sensorInterface.writeScratchpadAll(
TEMPERATURE_ALARM_LIMIT_HIGH,
TEMPERATURE_ALARM_LIMIT_LOW,
TEMPERATURE_RESOLUTION) != OneWireNg::ErrorCode::EC_SUCCESS) {
Serial.println("Failed to set temperature limits and resolution");
return;
}
didConfigureTemperatureSensors = true; didConfigureTemperatureSensors = true;
} }
@ -183,6 +189,7 @@ void temperaturePerformUpdate(Temperature* temperatures) {
for (const auto& id: (OneWireNg&) ow) { for (const auto& id: (OneWireNg&) ow) {
uint8_t sensorIndex = getSensorIndex(id); uint8_t sensorIndex = getSensorIndex(id);
if (sensorIndex == INVALID_SENSOR_INDEX) { if (sensorIndex == INVALID_SENSOR_INDEX) {
Serial.println("Invalid sensor");
// Invalid sensor id // Invalid sensor id
continue; continue;
} }
@ -190,10 +197,13 @@ void temperaturePerformUpdate(Temperature* temperatures) {
if (sensorInterface.readScratchpad(id, scratchpad) != OneWireNg::EC_SUCCESS) { if (sensorInterface.readScratchpad(id, scratchpad) != OneWireNg::EC_SUCCESS) {
// Invalid CRC // Invalid CRC
temperatures[sensorIndex].status = TemperatureStatus::sensorError; temperatures[sensorIndex].status = TemperatureStatus::sensorError;
Serial.println("Invalid CRC");
continue; continue;
} }
temperatures[sensorIndex].value = scratchpad->getTemp(); // In millidegrees Celcius temperatures[sensorIndex].value = scratchpad->getTemp(); // In millidegrees Celcius
temperatures[sensorIndex].status = TemperatureStatus::temperatureIsValid; temperatures[sensorIndex].status = TemperatureStatus::temperatureIsValid;
Serial.print(temperatures[sensorIndex].value);
Serial.println("°C");
} }
// Update missing sensors // Update missing sensors