Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement UI for multi-zone furnace controller #3

Open
wants to merge 69 commits into
base: furnace-controller
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
9b309b2
Refactor the UI controller, add test menu
tomikaa87 Jun 1, 2024
bdc8669
Menu: fix overdrawing
tomikaa87 Jun 2, 2024
e2c582d
Menu: implement upward stepping
tomikaa87 Jun 2, 2024
e308cbd
Implement an MVC-like UI architecture
tomikaa87 Jun 2, 2024
d229bd1
Modernize resource handling (fonts, assets)
tomikaa87 Jun 15, 2024
4e58422
Modernize large number drawing
tomikaa87 Jun 16, 2024
d738996
Remove DrawHelper
tomikaa87 Jun 16, 2024
ad8b8e2
Remove Text
tomikaa87 Jun 16, 2024
b13dbe1
Main screen
tomikaa87 Jun 16, 2024
9da4d4a
Add various settings screens
tomikaa87 Sep 24, 2024
00f9b40
Add more zone settings screens
tomikaa87 Sep 24, 2024
07f76e1
Implement new settings with fixed memory layout
tomikaa87 Sep 26, 2024
afb013e
Clean up settings logic in modules
tomikaa87 Sep 26, 2024
19f3cb5
Re-enable automatic display power saver
tomikaa87 Sep 26, 2024
645930d
Reduce amount of info logs
tomikaa87 Sep 26, 2024
4dea89d
Implement adjustable log level filter
tomikaa87 Sep 26, 2024
47a20a6
Change schedule bit order to MSB-first
tomikaa87 Sep 26, 2024
f7fb266
Implement zone schedule editing
tomikaa87 Sep 26, 2024
0d8ee1c
Add more schedule unit tests
tomikaa87 Sep 27, 2024
af07c43
Implement showing values on a menu item
tomikaa87 Sep 27, 2024
65c73ae
Implement display settings screen
tomikaa87 Sep 27, 2024
0102dc1
Implement general settings screen
tomikaa87 Sep 27, 2024
3763c4b
Implement zone settings screen
tomikaa87 Sep 27, 2024
1ef9a6f
Immediately apply display settings
tomikaa87 Sep 28, 2024
fbff585
Implement remaining zone settings
tomikaa87 Sep 28, 2024
d0159cf
Implement log level setting and reboot from main menu
tomikaa87 Sep 28, 2024
38f3091
Re-enable FurnaceController
tomikaa87 Sep 28, 2024
ff6b005
Bump version to 1.7.0
tomikaa87 Sep 28, 2024
abca102
Update esp-iot-base
tomikaa87 Sep 28, 2024
cfda0fe
Update data on Main Screen
tomikaa87 Sep 28, 2024
dc13bc8
Update zone controller clock
tomikaa87 Sep 28, 2024
313bc7f
Fix zone mode selection on settings screen
tomikaa87 Sep 28, 2024
7f41b55
Show zone status on main screen
tomikaa87 Sep 28, 2024
74e5edd
Fix log level setting roll-over
tomikaa87 Sep 28, 2024
c68bbd3
Disable debug mode zone temperature input
tomikaa87 Sep 28, 2024
5aca3f8
Remove unused ZoneGeneralSettingsScreen
tomikaa87 Sep 28, 2024
54c0eaa
Add missing WindowOpen state to zone status
tomikaa87 Sep 29, 2024
3dff83d
Add .editorconfig
tomikaa87 Sep 29, 2024
87593a7
Add MQTT packet buffer size requirement
tomikaa87 Sep 29, 2024
f5a7fee
Use custom fork of PubSubClient
tomikaa87 Sep 29, 2024
c797108
Add WindowLockout state to zone status
tomikaa87 Sep 29, 2024
0749fd9
Set MQTT packet buffer size
tomikaa87 Sep 29, 2024
7903ed3
Pre-allocate buffers for log strings
tomikaa87 Sep 29, 2024
c335321
Implement settings data versioning
tomikaa87 Sep 29, 2024
2484134
Implement adjustable window lockout duration
tomikaa87 Sep 29, 2024
668ab73
Add documentation for settings versioning
tomikaa87 Sep 29, 2024
6801b45
Revert to original PubSubClient temporaryly
tomikaa87 Sep 29, 2024
e0589ab
Bump version to 1.7.1
tomikaa87 Sep 29, 2024
c89bbeb
Add WiFi and MQTT states to the UI Model
tomikaa87 Sep 29, 2024
a2ea840
Add WiFi and MQTT connection status to main screen
tomikaa87 Sep 30, 2024
d3d68b5
Bump version to 1.7.2
tomikaa87 Sep 30, 2024
8a6da4d
Show 'Off' state on master disable
tomikaa87 Sep 30, 2024
4714cda
Bump version to 1.7.3
tomikaa87 Sep 30, 2024
174644b
Use custom PubSubClient (fixed)
tomikaa87 Sep 30, 2024
2cdb46d
Bump version to 1.7.4
tomikaa87 Sep 30, 2024
f669bbb
Create separate deploy environment
tomikaa87 Sep 30, 2024
6bca7b9
Fix static analysis issues
tomikaa87 Sep 30, 2024
c133432
Add separate screen for debugging
tomikaa87 Sep 30, 2024
5cd7fc3
Use manual menu capacity for memory efficiency
tomikaa87 Oct 1, 2024
9861846
Bump version to 1.7.5
tomikaa87 Oct 1, 2024
c71594f
Show zone number instead of index in settings
tomikaa87 Oct 1, 2024
3f2cb91
Bump version to 1.7.6
tomikaa87 Oct 1, 2024
e9f5c89
Use custom NTP server
tomikaa87 Oct 3, 2024
d00246a
Bump version to 1.7.7
tomikaa87 Oct 3, 2024
8c88e41
Remove old UI code
tomikaa87 Oct 4, 2024
c890df9
Remove unused configuration macros
tomikaa87 Oct 4, 2024
55726fe
Fix scrolling of long menus
tomikaa87 Oct 6, 2024
5de1ff5
Add input checks to HeatingZoneController
tomikaa87 Oct 6, 2024
51fb249
Bump version to 1.7.8
tomikaa87 Oct 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
[*]
cpp_indent_braces=false
cpp_indent_multi_line_relative_to=innermost_parenthesis
cpp_indent_within_parentheses=indent
cpp_indent_preserve_within_parentheses=false
cpp_indent_case_labels=false
cpp_indent_case_contents=true
cpp_indent_case_contents_when_block=false
cpp_indent_lambda_braces_when_parameter=false
cpp_indent_goto_labels=one_left
cpp_indent_preprocessor=leftmost_column
cpp_indent_access_specifiers=false
cpp_indent_namespace_contents=true
cpp_indent_preserve_comments=false
cpp_new_line_before_open_brace_namespace=new_line
cpp_new_line_before_open_brace_type=new_line
cpp_new_line_before_open_brace_function=new_line
cpp_new_line_before_open_brace_block=same_line
cpp_new_line_before_open_brace_lambda=same_line
cpp_new_line_scope_braces_on_separate_lines=false
cpp_new_line_close_brace_same_line_empty_type=false
cpp_new_line_close_brace_same_line_empty_function=false
cpp_new_line_before_catch=same_line
cpp_new_line_before_else=false
cpp_new_line_before_while_in_do_while=false
cpp_space_before_function_open_parenthesis=remove
cpp_space_within_parameter_list_parentheses=false
cpp_space_between_empty_parameter_list_parentheses=false
cpp_space_after_keywords_in_control_flow_statements=true
cpp_space_within_control_flow_statement_parentheses=false
cpp_space_before_lambda_open_parenthesis=false
cpp_space_within_cast_parentheses=false
cpp_space_after_cast_close_parenthesis=false
cpp_space_within_expression_parentheses=false
cpp_space_before_block_open_brace=true
cpp_space_between_empty_braces=false
cpp_space_before_initializer_list_open_brace=false
cpp_space_within_initializer_list_braces=true
cpp_space_preserve_in_initializer_list=true
cpp_space_before_open_square_bracket=false
cpp_space_within_square_brackets=false
cpp_space_before_empty_square_brackets=false
cpp_space_between_empty_square_brackets=false
cpp_space_group_square_brackets=true
cpp_space_within_lambda_brackets=false
cpp_space_between_empty_lambda_brackets=false
cpp_space_before_comma=false
cpp_space_after_comma=true
cpp_space_remove_around_member_operators=true
cpp_space_before_inheritance_colon=true
cpp_space_before_constructor_colon=true
cpp_space_remove_before_semicolon=true
cpp_space_after_semicolon=false
cpp_space_remove_around_unary_operator=true
cpp_space_around_binary_operator=insert
cpp_space_around_assignment_operator=insert
cpp_space_pointer_reference_alignment=left
cpp_space_around_ternary_operator=insert
cpp_wrap_preserve_blocks=one_liners
280 changes: 280 additions & 0 deletions doc/FurnaceControllerScreen.drawio

Large diffs are not rendered by default.

56 changes: 37 additions & 19 deletions lib/FurnaceController/HeatingZoneController.cpp
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
#include "HeatingZoneController.h"

#include <algorithm>

namespace
{
constexpr HeatingZoneController::DeciDegrees FailSafeLowTarget{ 100 };
constexpr HeatingZoneController::DeciDegrees FailSafeHighTarget{ 300 };
constexpr uint32_t OpenWindowLockoutDurationMs{ 10 * 60 * 1000 };

constexpr HeatingZoneController::DeciDegrees MinTargetTempHysteresis{ 1 };
constexpr HeatingZoneController::DeciDegrees MaxTargetTempHysteresis{ 10 };
}

HeatingZoneController::HeatingZoneController(
Configuration& config,
Schedule& schedule
const Configuration& config,
const Schedule& schedule
)
: _config{ config }
, _schedule{ schedule }
, _lastInputTemperature{ FailSafeHighTarget }
{
}
{}

void HeatingZoneController::updateDateTime(
const int dayOfWeek,
Expand All @@ -31,7 +34,7 @@ void HeatingZoneController::updateDateTime(

_scheduleDataDay = dayOfWeek;
_scheduleDataByte = intervalIndex >> 3;
_scheduleDataMask = 1 << (intervalIndex & 0b111);
_scheduleDataMask = 1 << (7 - (intervalIndex & 0b111));
}

void HeatingZoneController::setMode(const Mode mode)
Expand Down Expand Up @@ -79,6 +82,11 @@ void HeatingZoneController::inputTemperature(const DeciDegrees value)
_lastInputTemperature = value;
}

HeatingZoneController::DeciDegrees HeatingZoneController::lastInputTemperature() const
{
return _lastInputTemperature;
}

void HeatingZoneController::setHighTargetTemperature(const DeciDegrees value)
{
_highTargetTemperature = value;
Expand Down Expand Up @@ -147,7 +155,7 @@ std::optional<HeatingZoneController::DeciDegrees> HeatingZoneController::targetT
void HeatingZoneController::setWindowOpened(const bool open)
{
if (!open && _windowOpen) {
_openWindowLockoutRemainingMs = OpenWindowLockoutDurationMs;
_openWindowLockoutRemainingMs = _config.openWindowLockoutDurationSeconds * 1000;
} else if (open) {
_openWindowLockoutRemainingMs = 0;
}
Expand Down Expand Up @@ -187,13 +195,21 @@ bool HeatingZoneController::callingForHeating()
calculatedTargetTemperature = t.value();
}

if (_callForHeatingByTemperature) {
const auto target = calculatedTargetTemperature + _config.heatingOvershoot;
calculatedTargetTemperature = std::clamp(
calculatedTargetTemperature,
FailSafeLowTarget,
FailSafeHighTarget
);

if (
_lastInputTemperature >= target
|| _lastInputTemperature >= FailSafeHighTarget
) {
if (_callForHeatingByTemperature) {
const auto target = calculatedTargetTemperature
+ std::clamp(
_config.heatingOvershoot,
MinTargetTempHysteresis,
MaxTargetTempHysteresis
);

if (_lastInputTemperature >= target) {
_callForHeatingByTemperature = false;
}
} else {
Expand All @@ -204,12 +220,14 @@ bool HeatingZoneController::callingForHeating()
const auto target =
_furnaceHeating
? calculatedTargetTemperature
: calculatedTargetTemperature - _config.heatingUndershoot;

if (
_lastInputTemperature <= target
|| _lastInputTemperature <= FailSafeLowTarget
) {
: calculatedTargetTemperature -
std::clamp(
_config.heatingUndershoot,
MinTargetTempHysteresis,
MaxTargetTempHysteresis
);

if (_lastInputTemperature <= target) {
_callForHeatingByTemperature = true;

// Start the delay timer
Expand Down
40 changes: 36 additions & 4 deletions lib/FurnaceController/HeatingZoneController.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,33 @@ class HeatingZoneController

/**
* @brief Bit mask of high target temperature (30-minute slots) for 7 days.
* This structure is directly written into the settings memory.
* Be cautious when modifying this structure to avoid breaking data layout
* in existing devices. New fields should be added to the end of this structure.
* When data should be copied over from an existing field into a new one,
* or a new field should be initialized with a specific value,
* be sure to do a settings data version check and do the migration with the help
* of that.
*/
using Schedule = std::array<uint8_t, 6 * 7>;

/**
* @brief Essential controller configuration data.
* This structure is directly written into the settings memory.
* Be cautious when modifying this structure to avoid breaking data layout
* in existing devices. New fields should be added to the end of this structure.
* When data should be copied over from an existing field into a new one,
* or a new field should be initialized with a specific value,
* be sure to do a settings data version check and do the migration with the help
* of that.
*/
struct Configuration
{
uint32_t overrideTimeoutSeconds{ 120 * 60 };
uint32_t boostInitialDurationSeconds{ 30 * 60 };
uint32_t boostExtensionDurationSeconds{ 15 * 60 };
uint32_t heatingStartDelaySeconds{ 0 };
uint32_t openWindowLockoutDurationSeconds{ 600 };
DeciDegrees heatingOvershoot{ 5 };
DeciDegrees heatingUndershoot{ 5 };
DeciDegrees holidayModeTemperature{ 180 };
Expand All @@ -35,16 +53,28 @@ class HeatingZoneController
Holiday
};

/**
* @brief Controller state data.
* This structure is directly written into the settings memory.
* Be cautious when modifying this structure to avoid breaking data layout
* in existing devices. New fields should be added to the end of this structure.
* When data should be copied over from an existing field into a new one,
* or a new field should be initialized with a specific value,
* be sure to do a settings data version check and do the migration with the help
* of that.
*/
struct State
{
Mode mode{ Mode::Off };
DeciDegrees highTargetTemperature{ 220 };
DeciDegrees lowTargetTemperature{ 220 };

[[nodiscard]] bool operator<=>(const State&) const = default;
};

explicit HeatingZoneController(
Configuration& config,
Schedule& schedule
const Configuration& config,
const Schedule& schedule
);

void updateDateTime(int dayOfWeek, int hour, int minute);
Expand All @@ -64,6 +94,8 @@ class HeatingZoneController
*/
void inputTemperature(DeciDegrees value);

[[nodiscard]] DeciDegrees lastInputTemperature() const;

void setHighTargetTemperature(DeciDegrees value);
[[nodiscard]] DeciDegrees highTargetTemperature() const;

Expand Down Expand Up @@ -144,8 +176,8 @@ class HeatingZoneController
[[nodiscard]] bool startDelayActive() const;

private:
Configuration& _config;
Schedule& _schedule;
const Configuration& _config;
const Schedule& _schedule;

bool _stateChanged{ false };

Expand Down
74 changes: 52 additions & 22 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -11,42 +11,72 @@
[platformio]
extra_configs = lib/esp-iot-base/platformio.ini

[env:native]
platform = native
test_framework = googletest
build_flags = -std=c++20
[common]
build_flags =
-std=c++2a
-fconcepts
; ${iot.extra_release_flags}
; -Wall
-DIOT_ENABLE_PERSISTENCE
-DIOT_PERSISTENCE_EERAM_47L16
-DIOT_ENABLE_SYSTEM_CLOCK
-DIOT_SYSTEM_CLOCK_HW_RTC
-DIOT_ENABLE_MQTT
-DMQTT_MAX_PACKET_SIZE=2048
; -DDEBUG_ESP_PORT=Serial
; -DDEBUG_ESP_SSL
; -DDEBUG_ESP_HTTP_SERVER
; -DDEBUG_ESP_WIFI
; -DTEST_BUILD
; -DSIMPLE_I2C_DEBUG

build_unflags = -std=c++11 -std=gnu++17

[env:esp12e]
[env:esp_local_debug]
platform = [email protected]
board = esp12e
framework = arduino
upload_speed = 460800
monitor_speed = 74880
monitor_filters = esp8266_exception_decoder, default
test_framework = googletest
upload_resetmethod = nodemcu

build_flags =
${iot.build_flags}
${iot.release_flags}
${common.build_flags}
-DTEST_BUILD

lib_deps =
${iot.lib_deps}

#upload_resetmethod = nodemcu
build_unflags =
${common.build_unflags}

[env:esp_deploy]
platform = [email protected]
board = esp12e
framework = arduino
upload_speed = 460800
monitor_speed = 74880
monitor_filters = esp8266_exception_decoder, default
upload_protocol = espota
upload_port = furnace.iot.home
upload_flags = --auth="${sysenv.PIO_ESP_THERMOSTAT_AUTH}"

build_flags =
${iot.build_flags}
${iot.release_flags}
; ${iot.extra_release_flags}
; -Wall
-DIOT_ENABLE_PERSISTENCE
-DIOT_PERSISTENCE_EERAM_47L16
-DIOT_ENABLE_SYSTEM_CLOCK
-DIOT_SYSTEM_CLOCK_HW_RTC
-DIOT_ENABLE_MQTT
-DIOT_ENABLE_MQTT_EXTRA_LARGE_BUFFER
; -DDEBUG_ESP_PORT=Serial
; -DDEBUG_ESP_SSL
; -DDEBUG_ESP_HTTP_SERVER
; -DDEBUG_ESP_WIFI
; -DTEST_BUILD
; -DSIMPLE_I2C_DEBUG
${common.build_flags}

lib_deps =
${iot.lib_deps}
${iot.lib_deps}

build_unflags =
${common.build_unflags}

[env:unit_test]
platform = native
test_framework = googletest
build_flags = ${common.build_flags}
build_unflags = ${common.build_unflags}
8 changes: 2 additions & 6 deletions src/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,9 @@
Created on 2017-01-04
*/

#ifndef CONFIG_H
#define CONFIG_H
#include <IPAddress.h>

#define CONFIG_HEATCTL_SETTINGS_BASE_ADDR 0x00
#define CONFIG_SCHEDULER_SETTINGS_BASE_ADDR 0x10
#include "PrivateConfig.h"

#define CONFIG_USE_OLED_SH1106

#endif /* CONFIG_H */

Loading