Haha, you had me for a second there Bart. To me, HEMS means "Helicopter Emergency Medical Service". I have a friend who is a paramedic and did some tours on the London Air Ambulance. Now spends is working hours wizzing round London on a BMW paramedic motorbike.
Not sure about the full control/scheduling issue. That is a hard problem indeed. One easily dealt with by a human but not by a machine.
In regard to the data though, I have a similar issue for my new generation home automation system. So I've been building and documenting some standard data schema's to help me.
I have a known_devices
global that is highly technical but contains the metadata required to relate the device to the real world. For me, this is a human readable location and a description. So when I want to control a device, I only really need to expose the location (mostly there is only 1 relevant device in each location but there doesn't have to be). Then a web-page style controller or dashboard only needs to use the location and the system translates that to the actual device ID via the known_devices variable.
I also build out a locations variable where each location contains a property listing its devices split into 2, a switches
property listing the ID's of any switches (controllable plugs) in the location and a sensors
property listing the ID's of any sensor devices. This is just for convenience. The locations variable also maps the ID's of the smart heating systems locations as well.
I think that this is the type of data you would want in order to map human-friendly devices to system ID's.
Whether you can do this is going to depend on each device. For example, we have a dehumidifier, a simple one that plugs in and turns itself off when it reaches the required humidity. BUT you can't simply turn it off at the mains because that will damage it. You can turn it on remotely but not off. Same would be true for washing machines, dishwashers and driers. So whatever you come up with, you will need to have that logic built in and will need a property in your device data to say whether it can be prematurely turned off.
For the washer/drier rumpled cloths problem, you would likely need to know when SWMBO is out and when she will return. A very hard problem indeed!
Possibly another approach would be to have a dashboard that lets a human control things but with indicators provided by your system showing when the ideal time is likely to be. That way you can work on your ML and other controls without crashing the entire house and once (if ever) you get to a point when the system matches your experienced reality, you can then hand control over.
That one is probably more achievable though probably still has a lot of variables including expected weather conditions as well as expected power consumption.
ML requires vast amounts of training data to be useful. Especially so when dealing with chaotic systems (e.g. you and other household members coming and going). You will need to find ways to record people coming and going as a starting point. Not so bad if people have a fairly fixed schedule. However, COVID has completely destroyed any scheduled comings and goings in our house and even before then, our schedules varied quite a bit from week to week. Maybe your experience will be different.
In case it is of interest, here is the current known_devices schema - it may yet change slightly but I think I have most things set now:
/** Table of physical & logical IoT devices
* Used to track operational data for known devices.
* Used to map logical device names to physical ID's
* e.g. when setting `switch01`, mapping to physical ID and output channel to turn the relay on/off.
*/
known_devices: {
/* Object Key */
name: '{String} Unique',
/* Required Properties */
location: '{ENUM} Short description - see `locations` global',
id: '{String} <source>/<unique id>[-<Optional channel #>] Technical ID including leading protocol to ensure uniqueness',
input: '{Boolean} Does this device take input? e.g. a switch/relay/bell sounder',
output: '{Boolean} Does this device produce output? e.g. a sensor or a controller',
in_use: '{Boolean} Is this device actively being used?',
/* Optional Properties */
controls: '{Integer} Number of controls (buttons or sensors) that produce control output (e.g. to turn things on/off)',
sensors: '{String Array} Codes for all the sensors on board. See the `sensors` schema',
info: {
description: '{String} Description of device',
type: '{String} Description of device type',
source: '{ENUM} LAN, 433',
// For RFX devices (To send to RFX, `protocol/physical_id/id_channel`)
src_channel: '{ENUM} Input/Output channel from/to source. e.g. `RFX/lights`',
protocol: '{ENUM} EasyESP, LIGHTWAVERF, ...',
physical_id: '{String} Optional. e.g. hex id for 433mhz devices',
id_channel: '{Integer} Channel number for those devices that use settable channels (e.g. switches)',
// For networked devices
//protocol: '{String} description of protocol, e.g. `Tasmota`, `EasyESP`, `Custom`',
mac: '{String} Network MAC address of devices network interface. Only for LAN sources.',
ip: '{IP Address} IP Address of devices network interface. Only for Net or LAN sources.',
url: '{url} URL of web interface for the device. Only if it has one.',
// optional
AKA: '{String} If I/O from device also appears on a different ID',
geo: '{Array[lat,lon]} Geolocation of device'
},
/* Operational Data - added at runtime */
status: {
rssi: '{Integer} Measure of radio strength',
battery: '{Integer %} Measure of battery',
online: '{Boolean} Is the device considered to be online?',
updated: '{Timestamp}',
updated_by: '{String} What process/service updated the operational data?',
uptime: '',
memory: '',
last_restart: '',
last_restart_reason: '',
},
outputs: {
/* Sensor outputs - matches the sensor_types list */
'<sensor_name>': '{Number|Boolean|String} The value output from the sensor.'
},
inputs: {
/** Allows data/commands to be sent to IoT devices
* TODO: Need a way to define allowed input commands
*/
'<input_id>': {
state: '{On|Off} State of switch',
updated: '{Date} Last update of any kind',
last_on: '{Date} Last time of On status',
last_off: '{Date} Last time of Off status',
on_duration: '{Integer} ms elapsed between last on and last off',
off_duration: '{Integer} ms elapsed between last off and last on',
},
},
switches: {
/* Input Switch status & last on/off timestamps - 1 entry for each # controls */
'<switch_number>': {
state: '{On|Off} State of switch',
updated: '{Date} Last update of any kind',
last_on: '{Date} Last time of On status',
last_off: '{Date} Last time of Off status',
on_duration: '{Integer} ms elapsed between last on and last off',
off_duration: '{Integer} ms elapsed between last off and last on',
},
},
},