====== Implementing a Readily Deployed Autonomous Thermostat in 200 Lines of Code ====== The problem at hand is to develop the code for the mictrocontroller of an autonomous thermostat for a building with multiple rooms. The goal is to minimize power usage while ensuring that the temperature in each room is maintained at a comfortable level. The system must take into account various factors such as the current day of the week, time of the day, external temperature, and motion prediction in each room. Based on this data the system has to determine the radiator schedule for a number of time intervals. The goal of this example is of demonstrating how SOLVER-AI can be used to optimize energy usage in smart home systems. It showcases the use of predictive modeling in anticipating room occupancy and temperature changes, leading to more efficient energy usage. The system forecasts future states enabling it to make proactive decisions and optimize performance. The example also showcases how the system can intelligently adapt to changes in habits by uploading updated historical data. Don't forget to also have a look at [[examples:solar_plant_sizing|Implementing a Readily Deployed Solar Plant Sizing Tool in 400 Lines of Code]]. ---- ===== github ===== The clients with its examples can be downloaded from [[https://github.com/SOLVER-AI-LTD/client]]. The code can be found in: * C++: [[https://github.com/solver-ai-ltd/client/blob/master/cpp/example_thermostat.cpp|cpp/example_thermostat.cpp]] * python: [[https://github.com/solver-ai-ltd/client/blob/master/python/example_thermostat.py|/python/example_thermostat.py]] * JavaScript: [[https://github.com/solver-ai-ltd/client/blob/master/js/example_thermostat.js|js/example_thermostat.js]] ---- ===== Problem Detailed Description ===== Let's consider a building with ''numRooms'' number of rooms. We'll refer to ''i'' as the room number, with ''i'' being an integer in range [0, numRooms-1]. The building is fitted with an autonomous thermostat which: * Is connected to motion sensors in every room and gathers data stored in a //motionSensorData.csv// file at time intervals ''Dth'' (1/6 hour in the example). The file has as columns: * ''weekday'': Day of the week, integer in range [0, 6] where 0 is Monday and 6 is Sunday. * ''th'': Time of the day in hours, with range [0, 23.99]. * ''motion_i'': Motion in room ''i'', which has value 1 if motion was detected in the interval ''Dth'' and 0 if no motion was detected. * Is connected to temperature sensors in every room and also has a sensor to measure the external temperature. It collects data at time intervals ''Dth'' and stores it in a //temperatureSensorData.csv//, which has columns: * ''C_i'': State of the radiator in room ''i'', which has values 0 if off and 1 if on. * ''T_i'': Temperature in room ''i''. * ''Te'': External temperature. * ''DTh_i'': Temperature variation in room ''i'' in the time interval ''Dth''. * ''power'': Power consumption during interval ''Dth''. __**Objectives and Constraints**__ Considering ''numForecastIntervals'' times, spaced by Dth, our objective is to determine the radiator states ''C_i_j'' for each of the times ''th_j'' and ''weekday_j'', so that: * The total power consumption is minimized. * If motion is detected in room ''i'' the temperature is greater than a required temperature ''requiredT_j''. * If no motion is detected in room ''i'' the temperature is greater than a required ''Tmin_j''. ---- ===== Implementation ===== The implementation that can be found in the [[https://github.com/SOLVER-AI-LTD/client|code]] is as depicted in the image below, with ''N'' = ''numForecastIntervals'' - 1. {{ examples:thermostat.png?900,nolink |}} ;#; //Autonomous Thermostat Implementation (for room i).// ;#; The columns correspond to the different times ''j'', with each subsequent column at ''Dth'' time difference from the previous one. __**at j = 0**__ - The thermostat knows for each room ''i'': temperature ''T_i_0'', the current state of the radiators ''C_i_0'' and the external temperature. - //temperatureSensorData.csv// can be used for predicting ''DTh_i_0'' and ''power_0''. __**at j = 1**__ - We determine the time ''th_1'' and ''weekday_1'' by adding ''Dth'' to the previous time and weekday. - We determine the temperature ''T_i_1'' from ''DTh_i_0'' from the prediction at the previous step. - We consider the external temperature to still be ''Te''. - **Given unknown** ''C_i_1'' //temperatureSensorData.csv// can be used for predicting ''DTh_i_1'' and ''power_1''. __**at j, where j is greater or equal to 2 and smaller than N**__ - We determine the time ''th_j'' and ''weekday_j'' by adding ''Dth'' to the previous time and weekday. - We determine the temperature ''T_i_j'' from ''DTh_i_1'' from the prediction at the previous step. - We consider the external temperature to still be ''Te''. - **Given unknown** ''C_i_j'' //temperatureSensorData.csv// can be used for predicting ''DTh_i_j'' and ''power_j''. - //motionSensorData.csv// can be used for predicting ''motion_i_j''. - Given ''motion_i_j'' and the required temperature ''requiredT_i'' relative to room ''i'' : * If ''motion_i_j'' is greater than 0.4 (the probability of having movement is greater than 40%) then Tconstraint_i_j is the difference between the current temperature ''T_i_j'' and the requiredT_i temperature for room ''i''. * Otherwise, ''T_i_j'' is a large positive number. - Given the minimum temperature ''Tmin_i'', ''TconstraintMin_i_j'' is the difference between the current temperature ''T_i_j'' and the minimum temperature. __**at j = N = numForecastIntervals - 1**__ - We determine the time ''th_N'' and ''weekday_N'' by adding ''Dth'' to the previous time and weekday. - We determine the temperature ''T_i_N'' from ''DTh_i_1'' from the prediction at the previous step. - We consider the external temperature to still be Te. - //motionSensorData.csv// can be used for predicting ''motion_i_N''. - Given ''motion_i_N'' and the required temperature ''requiredT_i'' relative to room ''i'' : * If ''motion_i_N'' is greater than 0.4 (the probability of having movement is greater than 40%) then Tconstraint_i_N is the difference between the current temperature ''T_i_N'' and the requiredT_i temperature for room ''i''. * Otherwise, ''T_i_N'' is a large positive number. - Given the minimum temperature ''Tmin_i'', ''TconstraintMin_i_N'' is the difference between the current temperature ''T_i_N'' and the minimum temperature. Therefore, in order to perform this implementation, we need to set up: * //Equation// modules for ''th_j'' and ''weekday_j'' * //Equation// modules for ''Te_j'', where in this case we consider all of them equal to ''Te''. * A //SoftData// for the //temperatureSensorData.csv// with VectorizationIndices: 0 to ''numForecastIntervals'' - 2. * A //SoftData// for the //motionSensorData.csv// with VectorizationIndices: 2 to ''numForecastIntervals'' - 1. * //Equation// modules for computing ''T_i_j'' for ''j'' from 1 to ''numForecastIntervals'' - 1. * //Equation// modules for computing ''Tconstr_i_j'' for ''j'' from 2 to ''numForecastIntervals'' - 1. * //Equation// modules for computing ''TconstrMin_i_j'' for ''j'' from 2 to ''numForecastIntervals'' - 1. * An //Equation// module for computing ''power'' as the sum of the ''power_j'' for ''j'' from 1 to ''numForecastIntervals'' - 2. We'll then have to set: * As constants: * The time at which the calculation is performed (''th_0'', ''weekday_0'') and the the state values for ''j'' = 0, ''T_i_0'' for each room. * The required temperatures for each room ''requiredT_i''. * The minimum temperatures for each room ''Tmin_i''. * The interval ''Dth''. * As ranges: * The radiators controllers ''C_i_j'' for all rooms and ''i'' and ''j'' from 1 to ''numForecastIntervals'' - 2 to vary between 0 and 1 and be an integer. * As constraints: * Require that ''Tconstr_i_j'' is greater than 0 for ''j'' from 0 to ''numForecastIntervals'' - 1. * Require that ''TconstrMin_i_j'' is greater than 0 for ''j'' from 0 to ''numForecastIntervals'' - 1. * As objective: * ''power'' to be minimized. In the code we: - Create a //SolverAiClientSetup// object //solverAiClientSetup//. - Use the //solverAiClientSetup// object for creating all required modules and //Problem//. - Create a //SolverAiComputeInput// object input. - Use the //input// object to set up the //solverSetup//, constants, inputs, objectives and constraints. - Create a //SolverAiClientCompute// object //solverAiClientCompute//. - Run the computation with the //runSolver// function of the //solverAiClientCompute// object. __**Notes:**__ * The data provided for the example was generated so that: * The //temperatureSensorData.csv// file was created by specific heat transfer coefficients between rooms and definition of the positioning of the rooms. * The //motionSensorData.csv// file was created by specifying ranges of times within the week where motion was expected for each room on different days. A random number generator was then used so to produce I higher likelihood of motion during those periods. ---- ===== Extending the Code ===== The code provided in example_thermostat perform all of the operations, from createion of the modules and //Problem//, to execution, to deletion. This would obviously not be the case if this was implemented in reality. We could imagine that: - The thermostat could provide a server with the number of available sensors. The server would then call SOLVER-AI to setup modules and //Problem//. This would have to be performed only once at installation of the thermostat, or if additinal sensors were added to the system. - In operation, the thermostat would upload (update) the motion and temperature data on a daily / weekly basis to avoid performing the machine learning training, which is time-consuming. - A intermediary server should be interposed between the thermostat and SOLVER-AI to ensure the //token// is kept safe.