/* * * Copyright (c) 2021 Project CHIP Authors * Copyright (c) 2019 Google LLC. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ThermostaticRadiatorValveManager.h" #include "qvIO.h" #include #include "AppConfig.h" #include "AppTask.h" #include #include #include "gpSched.h" ThermostaticRadiatorValveManager ThermostaticRadiatorValveManager::sThermostaticRadiatorValve; using namespace chip; using namespace chip::app::Clusters; using namespace chip::DeviceLayer; TimerHandle_t sThermostaticRadiatorValveTimer; #if defined(CHIP_CONFIG_FREERTOS_USE_STATIC_TASK) && CHIP_CONFIG_FREERTOS_USE_STATIC_TASK StaticTimer_t sThermostaticRadiatorValveTimerBuffer; #endif #define DEGREE_FAHRENHEIT_CONVERSION(x) (int) ((float) x * 1.8) + 3200 // in unit of 0.01 #define DURATION_1SECOND 1000 // 1000 mseconds #define DURATION_1MIN 60 * DURATION_1SECOND #define TRV_MEASUREMENT_PERIOD DURATION_1MIN #define ONE_SECOND_US 1000000UL #define QPG_THERMOSTATIC_ENDPOINT_ID (1) static void DelayInit(void) { // measure temperature for the first time qvIO_MeasureTemperature(); // start operation ThermostaticRadiatorValveMgr().StartNormalOperation(); ThermostaticRadiatorValveMgr().SetAction(ThermostaticRadiatorValveManager::TRV_OFF_ACTION); } CHIP_ERROR ThermostaticRadiatorValveManager::Init() { ChipLogProgress(NotSpecified, "ThermostaticRadiatorValve init"); #if defined(CHIP_CONFIG_FREERTOS_USE_STATIC_TASK) && CHIP_CONFIG_FREERTOS_USE_STATIC_TASK sThermostaticRadiatorValveTimer = xTimerCreateStatic("ThermostaticRadiatorValveTmr", // Just a text name, not used by the RTOS kernel TRV_MEASUREMENT_PERIOD, // == default timer period (mS) true, // with timer reload (==periodic timer) (void *) this, // init timer id = ble obj context TimerEventHandler, // timer callback handler &sThermostaticRadiatorValveTimerBuffer // static buffer for timer ); #else // Create FreeRTOS sw timer for ThermostaticRadiatorValve timer. sThermostaticRadiatorValveTimer = xTimerCreate("ThermostaticRadiatorValveTmr", // Just a text name, not used by the RTOS kernel TRV_MEASUREMENT_PERIOD, // == default timer period (mS) true, // with timer reload (==periodic timer) (void *) this, // init timer id = lock obj context TimerEventHandler // timer callback handler ); #endif if (sThermostaticRadiatorValveTimer == NULL) { ChipLogProgress(NotSpecified, "sThermostaticRadiatorValveTimer timer create failed"); return APP_ERROR_CREATE_TIMER_FAILED; } // initiate temperature sensor here qvIO_TemperatureMeasurementInit(); gpSched_ScheduleEvent(ONE_SECOND_US, DelayInit); return CHIP_NO_ERROR; } void ThermostaticRadiatorValveManager::SetAction(Action_t action) { mThermostaticRadiatorValve_action = action; } void ThermostaticRadiatorValveManager::StartNormalOperation(void) { // start periodic timer if (mThermostaticRadiatorValve_action == TRV_OFF_ACTION) { ChipLogProgress(NotSpecified, "Start Normal Operation"); // update ThermostaticRadiatorValve status right away and start timer UpdateThermostaticRadiatorValveStatus(); // set timer period mPeriodicDuration = TRV_MEASUREMENT_PERIOD; // start timer StartTimer(mPeriodicDuration); } } void ThermostaticRadiatorValveManager::StopNormalOperation(void) { if (mThermostaticRadiatorValve_action > TRV_OFF_ACTION) { ChipLogError(NotSpecified, "Stop Normal Operation"); CancelTimer(); // set the action to OFF mThermostaticRadiatorValve_action = TRV_OFF_ACTION; } } void ThermostaticRadiatorValveManager::StartTimer(uint32_t aTimeoutMs) { ChipLogProgress(NotSpecified, "ThermostaticRadiatorValveTimer start timer with %lu", aTimeoutMs); if (xTimerIsTimerActive(sThermostaticRadiatorValveTimer)) { ChipLogError(NotSpecified, "app timer already started!"); CancelTimer(); } // timer is not active, change its period to required value (== restart). // FreeRTOS- Block for a maximum of 100 ticks if the change period command // cannot immediately be sent to the timer command queue. if (xTimerChangePeriod(sThermostaticRadiatorValveTimer, (aTimeoutMs / portTICK_PERIOD_MS), 100) != pdPASS) { ChipLogError(NotSpecified, "sThermostaticRadiatorValveTimer timer start() failed"); } } void ThermostaticRadiatorValveManager::CancelTimer(void) { if (xTimerStop(sThermostaticRadiatorValveTimer, 0) == pdFAIL) { ChipLogError(NotSpecified, "Lock timer timer stop() failed"); // appError(APP_ERROR_STOP_TIMER_FAILED); } } /* Timer event handler*/ void ThermostaticRadiatorValveManager::TimerEventHandler(TimerHandle_t xTimer) { // Get ThermostaticRadiatorValve obj context from timer id. ThermostaticRadiatorValveManager * thermostaticRadiatorValve = static_cast(pvTimerGetTimerID(xTimer)); // The timer event handler will be called in the context of the timer task // once sThermostaticRadiatorValveTimer expires. Post an event to apptask queue with the actual handler // so that the event can be handled in the context of the apptask. AppEvent event; event.Type = AppEvent::kEventType_Timer; event.TimerEvent.Context = thermostaticRadiatorValve; event.Handler = PeriodicTimerEventHandler; GetAppTask().PostEvent(&event); } /* periodic event handler */ void ThermostaticRadiatorValveManager::PeriodicTimerEventHandler(AppEvent * aEvent) { ThermostaticRadiatorValveManager * thermostaticRadiatorValve = static_cast(aEvent->TimerEvent.Context); ChipLogProgress(NotSpecified, "PeriodicTimerEventHandler"); // periodically check the temperature and update thermostaticRadiatorValve status thermostaticRadiatorValve->UpdateThermostaticRadiatorValveStatus(); } /* Read local temperature from temperature sensor */ int16_t ThermostaticRadiatorValveManager::GetLocalTemperature() { int temp = 0; // measure temperature through ADC peripheral qvIO_GetTemperatureValue(&temp); /* ADC module will be resume after SDP012-576*/ // measure temperature through ADC peripheral // ADC_GetTemperatureValue(&temp); ChipLogProgress(NotSpecified, "GetLocalTemperature (0.01 degC) - %d", temp); return (int16_t) temp; } /* Update the status of thermostaticRadiatorValve according to the existing attributes configuration and temperature */ void ThermostaticRadiatorValveManager::UpdateThermostaticRadiatorValveStatus(void) { int16_t localTemperature; int16_t heatingSetpoint; int16_t coolingSetpoint; ThermostaticRadiatorValveManager::SystemMode_t systemMode; ChipLogProgress(NotSpecified, "UpdateThermostaticRadiatorValveStatus"); mThermostaticRadiatorValve_action = TRV_IDLE_ACTION; // read temperature value and attributes localTemperature = GetLocalTemperature(); heatingSetpoint = GetOccupiedHeatingSetpoint(); coolingSetpoint = GetOccupiedCoolingSetpoint(); systemMode = GetSystemMode(); // check for the suitable action // Heat or Auto mode - start heating if temperature < heating setpoint // Cool or Auto mode - start cooling if temperature > cooling setpoint if (localTemperature < heatingSetpoint) { if ((systemMode == SystemMode_t::kAuto) || (systemMode == SystemMode_t::kHeat)) { // Example only - simply set the PI value to the different between local temperature and setpoint float delta = (float) (heatingSetpoint - localTemperature); float pi; pi = delta / heatingSetpoint * 100; SetPIHeatingDemand((uint8_t) pi); // configure LED qvIO_LedSet(SYSTEM_OPERATING_LED, true); // update the state mThermostaticRadiatorValve_action = TRV_HEATING_ACTION; } } else if (localTemperature > coolingSetpoint) { if ((systemMode == SystemMode_t::kAuto) || (systemMode == SystemMode_t::kCool)) { // Example only - simply set the PI value to the different between local temperature and setpoint float delta = (float) (localTemperature - coolingSetpoint); float pi; pi = delta / coolingSetpoint * 100; SetPICoolingDemand((uint8_t) pi); // configure LED qvIO_LedSet(SYSTEM_OPERATING_LED, true); // update the state mThermostaticRadiatorValve_action = TRV_COOLING_ACTION; } } if (mThermostaticRadiatorValve_action == TRV_IDLE_ACTION) { // no heating/cooling SetPICoolingDemand((uint8_t) 0); SetPIHeatingDemand((uint8_t) 0); qvIO_LedSet(SYSTEM_OPERATING_LED, false); } UpdateLocalTemperature(localTemperature); } void ThermostaticRadiatorValveManager::DisplayTemperature(void) { // Display the temperature using logging #ifdef GP_DIVERSITY_LOG int localTemperature; ThermostaticRadiatorValveManager::TempDisplayMode_t displaymode; ChipLogProgress(NotSpecified, "DisplayTemperature"); localTemperature = GetLocalTemperature(); displaymode = GetTemperatureDisplayMode(); if (displaymode == ThermostaticRadiatorValveManager::TempDisplayMode_t::kFahrenheit) { localTemperature = DEGREE_FAHRENHEIT_CONVERSION(localTemperature); ChipLogProgress(NotSpecified, "Temperature is %d.%02d degF", localTemperature / 100, localTemperature % 100); } else { ChipLogProgress(NotSpecified, "Temperature is %d.%02d degC", localTemperature / 100, localTemperature % 100); } #endif } /*================================================== Handling ThermostaticRadiatorValve cluster attributes ==================================================*/ void ThermostaticRadiatorValveManager::UpdateLocalTemperature(int16_t aLocalTemperature) { SystemLayer().ScheduleLambda([aLocalTemperature] { ChipLogProgress(NotSpecified, "UpdateLocalTemperature with value (0.01 degC) %u", aLocalTemperature); if (Protocols::InteractionModel::Status::Success != Thermostat::Attributes::LocalTemperature::Set(QPG_THERMOSTATIC_ENDPOINT_ID, aLocalTemperature)) { ChipLogProgress(NotSpecified, "UpdateLocalTemperature failure"); } }); } uint8_t ThermostaticRadiatorValveManager::GetPICoolingDemand(void) { uint8_t value; Thermostat::Attributes::PICoolingDemand::Get(QPG_THERMOSTATIC_ENDPOINT_ID, &value); ChipLogError(NotSpecified, "GetPICoolingDemand - %d", value); return value; } void ThermostaticRadiatorValveManager::SetPICoolingDemand(uint8_t aPI) { SystemLayer().ScheduleLambda([aPI] { Thermostat::Attributes::PICoolingDemand::Set(QPG_THERMOSTATIC_ENDPOINT_ID, aPI); ChipLogError(NotSpecified, "SetPICoolingDemand - %d", aPI); }); } uint8_t ThermostaticRadiatorValveManager::GetPIHeatingDemand(void) { uint8_t value; Thermostat::Attributes::PIHeatingDemand::Get(QPG_THERMOSTATIC_ENDPOINT_ID, &value); ChipLogError(NotSpecified, "GetPIHeatingDemand - %d", value); return value; } void ThermostaticRadiatorValveManager::SetPIHeatingDemand(uint8_t aPI) { SystemLayer().ScheduleLambda([aPI] { Thermostat::Attributes::PIHeatingDemand::Set(QPG_THERMOSTATIC_ENDPOINT_ID, aPI); ChipLogError(NotSpecified, "SetPIHeatingDemand - %d", aPI); }); } int16_t ThermostaticRadiatorValveManager::GetOccupiedCoolingSetpoint(void) { int16_t value; Thermostat::Attributes::OccupiedCoolingSetpoint::Get(QPG_THERMOSTATIC_ENDPOINT_ID, &value); ChipLogError(NotSpecified, "GetOccupiedCoolingSetpoint (0.01 degC) - %d", value); return value; } void ThermostaticRadiatorValveManager::SetOccupiedCoolingSetpoint(int16_t aSetpoint) { SystemLayer().ScheduleLambda([aSetpoint] { Thermostat::Attributes::OccupiedCoolingSetpoint::Set(QPG_THERMOSTATIC_ENDPOINT_ID, aSetpoint); ChipLogError(NotSpecified, "SetOccupiedCoolingSetpoint - %d", aSetpoint); }); } int16_t ThermostaticRadiatorValveManager::GetOccupiedHeatingSetpoint(void) { int16_t value; Thermostat::Attributes::OccupiedHeatingSetpoint::Get(QPG_THERMOSTATIC_ENDPOINT_ID, &value); ChipLogError(NotSpecified, "GetOccupiedHeatingSetpoint (0.01 degC) - %d", value); return value; } void ThermostaticRadiatorValveManager::SetOccupiedHeatingSetpoint(int16_t aSetpoint) { SystemLayer().ScheduleLambda([aSetpoint] { Thermostat::Attributes::OccupiedHeatingSetpoint::Set(QPG_THERMOSTATIC_ENDPOINT_ID, aSetpoint); ChipLogError(NotSpecified, "SetOccupiedHeatingSetpoint - status %d", aSetpoint); }); } ThermostaticRadiatorValveManager::Operation_t ThermostaticRadiatorValveManager::GetControlSequenceOfOperation(void) { ThermostaticRadiatorValveManager::Operation_t value; Thermostat::Attributes::ControlSequenceOfOperation::Get(QPG_THERMOSTATIC_ENDPOINT_ID, &value); ChipLogError(NotSpecified, "GetControlSequenceOfOperation - %d", (uint8_t) value); return value; } void ThermostaticRadiatorValveManager::SetControlSequenceOfOperation(ThermostaticRadiatorValveManager::Operation_t aOperation) { SystemLayer().ScheduleLambda([aOperation] { Thermostat::Attributes::ControlSequenceOfOperation::Set(QPG_THERMOSTATIC_ENDPOINT_ID, aOperation); ChipLogError(NotSpecified, "SetControlSequenceOfOperation value %d", (int) aOperation); }); } ThermostaticRadiatorValveManager::SystemMode_t ThermostaticRadiatorValveManager::GetSystemMode(void) { chip::app::Clusters::Thermostat::SystemModeEnum value; Thermostat::Attributes::SystemMode::Get(QPG_THERMOSTATIC_ENDPOINT_ID, &value); ChipLogError(NotSpecified, "GetSystemMode - %d", (uint8_t) value); return (ThermostaticRadiatorValveManager::SystemMode_t) value; } void ThermostaticRadiatorValveManager::SetSystemMode(ThermostaticRadiatorValveManager::SystemMode_t aSystemMode) { SystemLayer().ScheduleLambda([aSystemMode] { Thermostat::Attributes::SystemMode::Set(QPG_THERMOSTATIC_ENDPOINT_ID, aSystemMode); ChipLogError(NotSpecified, "SetSystemMode value %d", (uint8_t) aSystemMode); }); } ThermostaticRadiatorValveManager::TempDisplayMode_t ThermostaticRadiatorValveManager::GetTemperatureDisplayMode(void) { ThermostaticRadiatorValveManager::TempDisplayMode_t value; ThermostatUserInterfaceConfiguration::Attributes::TemperatureDisplayMode::Get(QPG_THERMOSTATIC_ENDPOINT_ID, &value); ChipLogError(NotSpecified, "GetTemperatureDisplayMode - %d", (uint8_t) value); return value; } void ThermostaticRadiatorValveManager::SetTemperatureDisplayMode(ThermostaticRadiatorValveManager::TempDisplayMode_t aMode) { SystemLayer().ScheduleLambda([aMode] { ThermostatUserInterfaceConfiguration::Attributes::TemperatureDisplayMode::Set(QPG_THERMOSTATIC_ENDPOINT_ID, aMode); ChipLogError(NotSpecified, "SetTemperatureDisplayMode value %d", (uint8_t) aMode); }); } // Reserved for future use void ThermostaticRadiatorValveManager::SetCallbacks(ThermostaticRadiatorValveCallback_fn aActionInitiated_CB, ThermostaticRadiatorValveCallback_fn aActionCompleted_CB) { mActionInitiated_CB = aActionInitiated_CB; mActionCompleted_CB = aActionCompleted_CB; }