Fix unexpected issues
This commit is contained in:
parent
40775d53cf
commit
49f4d24242
@ -49,10 +49,10 @@ namespace ranczo {
|
||||
enum class ThermostatState { Enabled, Disabled, Error };
|
||||
enum class Trend { Fall, Const, Rise };
|
||||
|
||||
std::optional<ThermostatState> ThermostatState_from_string(std::string_view state){
|
||||
std::optional< ThermostatState > ThermostatState_from_string(std::string_view state) {
|
||||
std::string s(state.begin(), state.end());
|
||||
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return static_cast< char >(std::tolower(c)); });
|
||||
|
||||
|
||||
if(s == "enabled")
|
||||
return ThermostatState::Enabled;
|
||||
if(s == "disabled")
|
||||
@ -62,8 +62,8 @@ std::optional<ThermostatState> ThermostatState_from_string(std::string_view stat
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::string ThermostatState_to_string(ThermostatState state){
|
||||
switch (state) {
|
||||
std::string ThermostatState_to_string(ThermostatState state) {
|
||||
switch(state) {
|
||||
case ThermostatState::Enabled:
|
||||
return "Enabled";
|
||||
case ThermostatState::Disabled:
|
||||
@ -95,7 +95,7 @@ inline expected< T > readValue(const boost::json::value & jv, std::string_view k
|
||||
if(not v)
|
||||
return unexpected{make_error_code(boost::system::errc::invalid_argument)};
|
||||
return *v;
|
||||
|
||||
|
||||
} else if constexpr(is_chrono_duration_v< T >) {
|
||||
if(pv->is_string()) {
|
||||
auto sv = pv->as_string();
|
||||
@ -358,7 +358,7 @@ struct RelayThermostat::Impl : private boost::noncopyable {
|
||||
private:
|
||||
executor & _io;
|
||||
AsyncMqttClient & _mqtt;
|
||||
|
||||
|
||||
ComponentSettingsStore _settings;
|
||||
|
||||
/// relay control
|
||||
@ -454,7 +454,8 @@ struct RelayThermostat::Impl : private boost::noncopyable {
|
||||
}
|
||||
|
||||
auto trend = *trendOpt;
|
||||
const bool relayOn = (_relay->state() == Relay::State::On);
|
||||
auto st = ASYNC_TRY(_relay->state());
|
||||
const bool relayOn = (st == Relay::State::On);
|
||||
|
||||
// 2a) relay OFF, a temperatura rośnie => przekaźnik zawiesił się na ON
|
||||
if(!relayOn && trend == Trend::Rise) {
|
||||
@ -470,7 +471,8 @@ struct RelayThermostat::Impl : private boost::noncopyable {
|
||||
}
|
||||
|
||||
awaitable_expected< void > handleErrorState() {
|
||||
if(_relay->state() == Relay::State::On) {
|
||||
auto st = ASYNC_TRY(_relay->state());
|
||||
if(st == Relay::State::On) {
|
||||
spdlog::warn("Forcing relay OFF in ERROR state for {}/{}", _room, _zone);
|
||||
ASYNC_CHECK_MSG(_relay->off(), "Emergency relay OFF failed!");
|
||||
}
|
||||
@ -478,7 +480,8 @@ struct RelayThermostat::Impl : private boost::noncopyable {
|
||||
}
|
||||
|
||||
awaitable_expected< void > handleDisabledState() {
|
||||
if(_relay->state() == Relay::State::On) {
|
||||
auto st = ASYNC_TRY(_relay->state());
|
||||
if(st == Relay::State::On) {
|
||||
spdlog::info("RelayThermostat disabling relay because thermostat is Disabled for {}/{}", _room, _zone);
|
||||
ASYNC_CHECK_MSG(_relay->off(), "relay OFF failed");
|
||||
}
|
||||
@ -496,7 +499,8 @@ struct RelayThermostat::Impl : private boost::noncopyable {
|
||||
|
||||
const auto now = system_clock::now();
|
||||
const auto minElapsed = now - _lastStateChange;
|
||||
const bool relayOn = (_relay->state() == Relay::State::On);
|
||||
auto st = ASYNC_TRY(_relay->state());
|
||||
const bool relayOn = (st == Relay::State::On);
|
||||
|
||||
// grzejemy jeżeli temp < setpoint - histereza
|
||||
if(!relayOn) {
|
||||
@ -537,7 +541,8 @@ struct RelayThermostat::Impl : private boost::noncopyable {
|
||||
_state = ThermostatState::Error;
|
||||
|
||||
// Bezpieczeństwo: wyłącz przekaźnik natychmiastowo
|
||||
if(_relay->state() == Relay::State::On) {
|
||||
auto st = ASYNC_TRY(_relay->state());
|
||||
if(st == Relay::State::On) {
|
||||
ASYNC_CHECK(_relay->off());
|
||||
}
|
||||
|
||||
@ -549,12 +554,18 @@ struct RelayThermostat::Impl : private boost::noncopyable {
|
||||
public:
|
||||
Impl(executor & io,
|
||||
AsyncMqttClient & mqtt,
|
||||
SettingsStore &setup,
|
||||
SettingsStore & setup,
|
||||
std::unique_ptr< Relay > relay,
|
||||
std::unique_ptr< Thermometer > thermometer,
|
||||
std::string_view room,
|
||||
int zone)
|
||||
: _io{io}, _settings{setup, std::string{room}}, _mqtt{mqtt}, _relay{std::move(relay)}, _thermo{_io, std::move(thermometer)}, _room{room}, _zone{zone} {
|
||||
: _io{io},
|
||||
_settings{setup, std::string{room}},
|
||||
_mqtt{mqtt},
|
||||
_relay{std::move(relay)},
|
||||
_thermo{_io, std::move(thermometer)},
|
||||
_room{room},
|
||||
_zone{zone} {
|
||||
BOOST_ASSERT(_relay);
|
||||
BOOST_ASSERT(not _room.empty());
|
||||
BOOST_ASSERT(_zone > 0);
|
||||
@ -565,42 +576,40 @@ struct RelayThermostat::Impl : private boost::noncopyable {
|
||||
awaitable_expected< void > start() {
|
||||
using namespace std::placeholders;
|
||||
spdlog::info("RelayThermostat::start room : {}", _room);
|
||||
|
||||
|
||||
auto get_state = [this](std::string key, ThermostatState _default) -> awaitable_expected<ThermostatState>{
|
||||
|
||||
auto get_state = [this](std::string key, ThermostatState _default) -> awaitable_expected< ThermostatState > {
|
||||
auto contains = ASYNC_TRY(_settings.async_contains(key));
|
||||
if(not contains){
|
||||
if(not contains) {
|
||||
ASYNC_CHECK(_settings.async_save(key, ThermostatState_to_string(_default)));
|
||||
}
|
||||
|
||||
|
||||
/// TODO can throw
|
||||
auto value = ASYNC_TRY(_settings.async_get(key)).value(); // we have this value at this point
|
||||
auto ThermostatStateStr = value.get_if<std::string>(); // TODO can be different type
|
||||
auto state = ThermostatState_from_string(ThermostatStateStr);
|
||||
auto value = ASYNC_TRY(_settings.async_get(key)).value(); // we have this value at this point
|
||||
auto ThermostatStateStr = value.get_if< std::string >(); // TODO can be different type
|
||||
auto state = ThermostatState_from_string(ThermostatStateStr);
|
||||
if(state)
|
||||
co_return *state;
|
||||
co_return unexpected{make_error_code(boost::system::errc::invalid_argument)};
|
||||
};
|
||||
|
||||
auto get_double = [this](std::string key, double _default) -> awaitable_expected<double>{
|
||||
|
||||
auto get_double = [this](std::string key, double _default) -> awaitable_expected< double > {
|
||||
auto contains = ASYNC_TRY(_settings.async_contains(key));
|
||||
if(not contains){
|
||||
if(not contains) {
|
||||
ASYNC_CHECK(_settings.async_save(key, _default));
|
||||
}
|
||||
|
||||
|
||||
/// TODO can throw
|
||||
auto value = ASYNC_TRY(_settings.async_get(key)).value(); // we have this value at this point
|
||||
co_return value.get_if<decltype(_default)>(); // TODO can be different type
|
||||
co_return value.get_if< decltype(_default) >(); // TODO can be different type
|
||||
};
|
||||
|
||||
_state = ASYNC_TRY(get_state("state", ThermostatState::Disabled));
|
||||
|
||||
_state = ASYNC_TRY(get_state("state", ThermostatState::Disabled));
|
||||
_targetTemperature = ASYNC_TRY(get_double("target_temperature", 20.0));
|
||||
_hysteresis = ASYNC_TRY(get_double("hysteresis",2));// [°C]
|
||||
_hysteresis = ASYNC_TRY(get_double("hysteresis", 2)); // [°C]
|
||||
std::chrono::nanoseconds _tickTime{std::chrono::seconds(60)}; // minimalny czas ON/OFF
|
||||
std::chrono::nanoseconds _slopeWindow{std::chrono::minutes(5)};
|
||||
_slopeDT_c = ASYNC_TRY(get_double("slope_delta_t", 1));// [°C / min]
|
||||
std::chrono::minutes _sensorTimeout{std::chrono::minutes(5)};
|
||||
|
||||
_slopeDT_c = ASYNC_TRY(get_double("slope_delta_t", 1)); // [°C / min]
|
||||
std::chrono::minutes _sensorTimeout{std::chrono::minutes(5)};
|
||||
|
||||
// subscribe to a thermostat commands feed
|
||||
spdlog::info("RelayThermostat::start room : {} subscribe to mqtt", _room);
|
||||
@ -624,12 +633,12 @@ struct RelayThermostat::Impl : private boost::noncopyable {
|
||||
}
|
||||
|
||||
awaitable_expected< void > subscribeToAllCommands() {
|
||||
ASYNC_TRY(subscribeCommand< commands::TemperatureSetpointChange >());
|
||||
ASYNC_TRY(subscribeCommand< commands::StateChange >());
|
||||
ASYNC_TRY(subscribeCommand< commands::HisteresisChange >());
|
||||
ASYNC_TRY(subscribeCommand< commands::TickTimeChange >());
|
||||
ASYNC_TRY(subscribeCommand< commands::SlopeWindowChange >());
|
||||
ASYNC_TRY(subscribeCommand< commands::SlopeTemperatureDiffChange >());
|
||||
ASYNC_CHECK(subscribeCommand< commands::TemperatureSetpointChange >());
|
||||
ASYNC_CHECK(subscribeCommand< commands::StateChange >());
|
||||
ASYNC_CHECK(subscribeCommand< commands::HisteresisChange >());
|
||||
ASYNC_CHECK(subscribeCommand< commands::TickTimeChange >());
|
||||
ASYNC_CHECK(subscribeCommand< commands::SlopeWindowChange >());
|
||||
ASYNC_CHECK(subscribeCommand< commands::SlopeTemperatureDiffChange >());
|
||||
|
||||
co_return _void{};
|
||||
}
|
||||
@ -673,14 +682,15 @@ struct RelayThermostat::Impl : private boost::noncopyable {
|
||||
spdlog::warn("Ignoring attempt to enable thermostat in ERROR state for {}/{}", _room, _zone);
|
||||
co_return _void{};
|
||||
}
|
||||
|
||||
|
||||
_state = cmd.state;
|
||||
|
||||
// Bezpiecznik: jeśli zostało ustawione Disabled – wyłącz przekaźnik
|
||||
if(_state == ThermostatState::Disabled && _relay->state() == Relay::State::On) {
|
||||
|
||||
// Bezpiecznik: jeśli zostało ustawione Disabled – wyłącz przekaźnik
|
||||
auto st = ASYNC_TRY(_relay->state());
|
||||
if(_state == ThermostatState::Disabled && st == Relay::State::On) {
|
||||
ASYNC_CHECK(_relay->off());
|
||||
}
|
||||
|
||||
|
||||
co_return _void{};
|
||||
}
|
||||
|
||||
@ -711,14 +721,12 @@ struct RelayThermostat::Impl : private boost::noncopyable {
|
||||
|
||||
RelayThermostat::RelayThermostat(executor & io,
|
||||
AsyncMqttClient & mqtt,
|
||||
SettingsStore &setup,
|
||||
SettingsStore & setup,
|
||||
std::unique_ptr< Relay > relay,
|
||||
std::unique_ptr< Thermometer > thermometer,
|
||||
std::string_view room,
|
||||
int zone_id)
|
||||
: _impl{std::make_unique< Impl >(io, mqtt, setup, std::move(relay), std::move(thermometer), room, zone_id)} {
|
||||
|
||||
}
|
||||
: _impl{std::make_unique< Impl >(io, mqtt, setup, std::move(relay), std::move(thermometer), room, zone_id)} {}
|
||||
|
||||
RelayThermostat::~RelayThermostat() = default;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user