Documentation: A sTale As Old As Time

Documentation: it is the key to our tools. It has enabled us to evolve from coding into the prominent engineers on the planet. Documentation is slow, normally taking as much, if not more, time than the development itself. But every few hundred commits, development leaps forward – leaving documentation behind.

Professor Xavier, X-Men (if he were a software engineer rather than a mutant geneticist)

There is a war brewing; between those who put their faith in the documentation and those who fear the prophecies the staleness to come.

Documentation: Self-Documenting or Well-Documented

Do you think the thorough and comprehensive documentation of your project is enough to understand how to interact with it?

Do you think your code is so clean and intuitive that anyone can interface with it?

Everyone is wrong, and those who value tribal knowledge are toeing the line of true evil – but let’s leave them in the hole that they are digging for themselves. Every project starts with aspirations of perfection and standards of quality; admirable but completely unrealistic and unattainable.

Stale documentation absolutely will happen to your project. There is no way that documentation can be maintained at the same level and speed as the features and bug fixes – deadlines and goals change, small bits slip through the cracks. When it comes to documentation, words are nothing but representations of abstract ideas that no two people perceive in the same manner. No matter how thorough or complete you feel your documentation is, there will be those who do not understand; the more thorough your documentation, the harder it is to maintain.

Code is logical, as well as the currently defined instruction set, making the concept of self-documenting code more appetizing. Yet, code is an art and interpreted by the individual, understood at different levels, and can appear to be absolute magic – and a magician never reveals their secret (hint: it’s a reflection). What is intuitive to me is not intuitive to you, and if we wrote code to be so intuitive and easy to pick up….. well we can’t. Even Blockly and Scratch, which are intended to introduce children to programming concepts, seem alien to many – then when you introduce concepts like Aspect-Oriented Programming and Monkey Patching, you have entered the realm most dare not.

So, yes, the documentation for your library, REST API or plugin will, at some point, fail. End of story.

Documentation or Self-Documenting - neither can guarantee full understanding to others.

Pitch the Stale Documentation, Having the Ripe Idea

Credit where credit is due, this concept was not of mine but of my best friend James. He had grown tired of outdated, incorrect, or flat-out misleading API documentation. Most documentation aggregation software collects information from conformingly formatted comments – JavaDoc, API Doc, C# XML – but comments are not meant to be ingested by the application they are describing and are often the first to be forgotten when there is a fire burning. We have accepted that Tests should not be a second-class citizen, Test Driven Development is a proven standard, and we should not accept documentation to be either.

There’s a motto amongst software engineers “never trust your input”; but all this validating, verifying, authenticating… it’s boring, I am lazy and why can’t it just validate itself and let me move on to the fun part?

To focus on the fun part, you have to automate the boring stuff.

Swagger is a specification for documenting REST APIs down to every detail: payload definitions, request specifications, conditional arguments, content-type, required permissions, return codes – everything. The best part? The specification is consumable. Swagger even includes a browseable user interface that describes every facet and even lets you interact with the server visually. Play with a live demo yourself.

In Douglas Adams’ Hitchhiker’s Guide to the Galaxy, the Magrathean’s designed and built a computer to provide the ultimate answer; the answer to Life, the Universe, and Everything. This computer’s name? Deep Thought. An apt name for a library that would handle the answer, as long as you handled the question. Our proof of concept, DeeptThought-Routing, accepted your Swagger JSON specification along with endpoint handlers and a permissions provider as parameters and generated a NodeJS router that would validate paths, payloads, permissions even parsing the request against the Content-Type header and transforming the handler output to the Accepts header MIME type – not to mention attempt to transform or coerce parameters to the specification data types; returning the appropriate HTTP response codes without invoking your handlers. You could trust your inputs, no validation, free to focus on the core of the project – the fun part.

DeepThought: Documentation Driven Development

Schema-First means you define the schema (or specification) for your code, then utilize tooling that generates the code that matches the definitions, constraints, and properties within your schema. Through DeepThought-Routing, we had proven the concept of self-validation. Swagger did the same for self-documenting. Code generation is a core concept to GraphQL and JSON-Schema lists language-specific tooling for code generation.

There’s a pattern to all of this, patterns can be automated. A spark appeared in my mind: “Instead of implicit meaning through validation of inputs and documentation of primitive data types – what if the meaning were explicit, and if the meaning is explicit, they could validate themselves!” That spark became an inferno of chaining the initial “what-if” to “if that, then we could…”. When the fire of inspiration slowly receded to glowing embers, what was left was an idea. An idea that could change how software development is approached, at least, how I would approach development: Documentation Driven Development.

The Goals for Documentation Driven Development:

  • Self-Documenting: Clean, human readable documentation generated directly from the schema
  • Self-Describing: Meta-datatypes that provide meaning to the underlying data through labels and units
  • Self-Validating: Generates data models that enforce the constraints defined in the schema
  • Self-Testing: Unit tests are generated to test against constraints in models and data structures
  • UseCase-Scaffolding: Generates the signature of the functions that interact with external interfaces, and interface with the domain of your application
  • Correctness-Validation: Validates the units/labels of input model parameters can yield the units/labels of the use case output
  • Language-Agnostic: Plugin-based system for generation of code and documentation

Obviously, this is a large undertaking and still in its infancy – but I can see the path that will bring Documentation Driven Development from abstract concept to reality.

Example Schema

Here is a simplified example of how to model a submersible craft with meaningful data fields and perform an action on the speed of the craft.

Units

id: fathom
name: Fathoms
description: A length measure usually referring to a depth.
label:
  single: fathom
  plural: fathoms
  symbol: fm
conversion:
  unit: meter
  conversion: 1.8288

Unit Validating Meta-Schema Specification: https://github.com/constructorfleet/Deepthought-Schema/blob/main/meta-schema/unit.meta.yaml

Compound Units

id: knot
name: Knot
description: The velocity of a nautical vessel
symbol: kn
unit:  # The below yields the equivalent of meter/second
  unit: meter
  dividedBy:
    unit: second  
# Example for showing the extensibility of compound units
id: gravitational_constant
name: Gravitational Constant Units
description: The units for G, the gravitational constant
label:
  single: meter^3 per (kilogram * second^2)
  plural: meters^3 per (kilogram * second^2)
  symbol: m^3/(kg*s^2)
unit:
  unit: meter
  exponent: 3
  dividedBy:
    group:
      unit: kilogram
      multipliedBy:
        unit: second
        exponent: 2

Compound Unit Validating Meta-Schema Specification: https://github.com/constructorfleet/Deepthought-Schema/blob/main/meta-schema/compound-units.meta.yaml

Fields

id: depth
name: Depth
description: The depth of the submersible
dataType: number
unit: fathom
constraints:
- minimum:        # Explicit unit conversion
    value: 0
    unit: fathom
- maximum: 100    # Implicit unit conversion
- precision: 0.1  # Implicit unit conversion

id: velocity
type: number
name: Nautical Speed
description: The velocity of the craft moving
unit: knot
constraints:
  - minimum: 0
  - maximum: 12

Field Validating Meta-Schema Specification: https://github.com/constructorfleet/Deepthought-Schema/blob/main/meta-schema/field.meta.yaml

Models

id: submersible
name: Submarine Craft
description: A craft that can move through an aquatic medium
fields:
  - depth
  - velocity

Use Cases

id: adjust_submersible_speed
name: Adjusts the nautical speed of the craft
input:
  - submersible
  - speed
output:
  - submersible

You Have Questions, I Have a Few Answers

What the heck is a meaningful meta-datatype?

Traditionally, a field’s specification is broad, abstract, or meaningless which leads to writing documentation that attempts to provide meaning to the consumer of the code. We know what an Integer, Float, Byte, String, etc. are – but these are just labels we apply to ways of storing and manipulating data. If the author provides sufficient information regarding the acceptable values, ranges, and edge case – there is still the matter of writing a slew of tests to ensure the fields lie within the specifications. Not to mention, hoping the documentation remains in line with the implementation as teams, features, and requirements change and grow.

While still using the same underlying storage and manipulations considered familiar across the landscape, fields in DeepThought attempt to remove the tediousness, prevent stale documentation, as well as describing what is. Each field specifies a code-friendly reference name, a human-readable meaningful name, description, constraints, coercive manipulations of the underlying data type – plus units if applicable.

What if I don’t want or need units?

That’s perfectly fine! Obviously, you will lose some of the validation that arises from your schema. Not to mention that unit-less scalars and unit-less physical constants are absolutely a thing, along with physical constants.

How can you validate “correctness” of the Use Cases?

When specifying Use Cases, Deepthought has no knowledge of your implementation. Be it a single method, a chain of methods – that is up to you. Specify the input models, and the output model – knowing you can trust that your input is valid, tested, and in the exact form that is expected. Through dimensional analysis, it is possible to determine if the output model’s units are possible given the input models’ units. If dimensionally correct, DeepThought will generate the scaffolded code for you to implement – if incorrect, you will know before you even start coding.

Follow the Progress of DeepThought

I welcome all input – positive, negative, suggestions, complaints. While I am building this for myself, it would bring me great pleasure to see this adopted by others.

Happy Fishes through Nature Automation

Nature Automation: Life’s Built-In Automation Engine

Humans have been bending nature to their whim since the dawn of civilization, and it is a full-time job for many keeping nature out of the way. Alan and I learned this firsthand over the course of the last year and wish to share the lessons we learned with others: trust Nature Automation and your aquatic pets will thank you.

A Cautionary Tale: Fighting Against Nature Automation

Admiral Shiny Sides and the His First Mate Tank

Admiral Shiny Side, sadly, passed away in the heat of battle during his 5th deployment after 16 years of loyal service; posthumously promoted to Fleet Admiral Shiny Sides. His first mate, Tank, failed to lead with the same authority and followed Admiral Shiny Sides not long after. Ensign Alan fought the lonely and uphill battle of maintaining the ship since its inception: swabbing the poop rocks, manning the main filters, and keeping the mess hall fully stocked.

Tank was assigned three new recruits upon the passing of Fleet Admiral Shiny Sides. Morale amongst the crew never recovered, even while the valiant Ensign Alan took on the task of making the long journey at sea as comfortable as possible. In the end, the effort to uphold the same standards proved fruitless. One by one they succumbed to the siren’s seductive song.

They will be missed.

If you’re confused, that’s understandable; Admiral Shiny Sides and his first mate were Alan’s goldfish for 16 years, which I, for one, had no idea they could live such long and fulfilling lives. Moving in marked their 5th home move, and it was just too much for these intrepid sailors – and nearly triggered the retirement of the battle-hardened S.S. Aquarium.

The Road to Recovery is Long and Hard

Taking care of fish can be a lot of work: vacuuming the waste, replacing filters, cleaning out algae, addressing illness, and feeding. The aquarium was always Alan’s project, and provided a very clear indication of his general mood; when stressed or overburdened, the aquarium maintenance would be put on hold and only further the level of stress he experienced. The loss of our fish was conflicting, we loved our pets but the effort to maintain the equilibrium violated the prime directive of laziness that permeates our existence.

We decided to start over. After lots of research, we drained the aquarium, replaced the gravel, and focused on keeping some aquarium plants alive before we put any more naval recruits in mortal danger. After 2 months, our plants were thriving and it was time to assign a new crew to the S.S. Aquarium – this time, we sought expert advice from the employees of Aquamart. One of their friendly staff taught us how to use the ecosystem through bio-filters and the right blend of aquatic species to be introduced slowly to implement nature automation.

The road to recovery is far from a linear journey. We did lose a few recruits along the way, but such is life – there’s no guarantee any of us, animals included, will live long and healthy lives. These losses were very hard for us animal lovers, but we know we did our best. The first live fish we introduced were a few Corydoras, these are small, bottom-feeder, freshwater catfish – unfortunately for them, the tank was not quite as stable as we thought, and we ended up losing all three of them. Their loss was not in vain. Researching their symptoms and what solutions were available, we switched to SeaChem for, essentially, all of our aquarium treatments. We have suffered other losses, but only to those fish we ordered online and perished in transport.

Our aquarium is a thriving ecosystem now, requiring only basic maintenance. Gone are the evenings dedicated to 3-4 hours of tending to the aquarium. We devote around 20 minutes every few weeks to replenishing water that has evaporated and rinsing off the bio-filters. We do add some chemicals every so often: plant food, liquid CO2, stress-reducers – but we do so while we are admiring our beautiful fish. Thriving so well, we discovered we accidentally purchased two female guppies when we came home from vacation to around 12 tiny baby fantails that are now starting to show their colors!

Why Did We Succeed Where We Failed Before

Fleet Admiral Shiny Sides, Tank, and their crew were very dirty. Goldfish are prone to polluting their tank with nitrates and ammonia. Choosing the appropriate species helps reduce toxins and waste present in your underwater ecosystem. In addition to reducing the pollutants, these aquarium fish are much more active and colorful, creating living art that we love to admire daily.

Algae are actually bacteria that contain chlorophyll and require many of the same resources that are consumed by plants. Originally we planted plastic and silicone plants in our aquarium; by planting living plants there are little-to-no resources left for algae to consume. Common sense right? Except, it’s not. It’s amazing how many people, including ourselves, are willing to dedicate hours every month cleaning and removing algae from their water-dwelling pets’ homes.

Carbon filters are a complete waste of time and money – bio-filters promote healthy bacteria and reduce harmful bacteria. Sure, carbon filters remove solid waste and help cleanse the water, but fish, like humans, do not live in a hermetically sealed environment. You can purchase a bio-wheel filter from most pet stores, however, we discovered them to be fragile and ineffective. As our helpful Aquamart employee explained, utilizing bio-media rocks to remove ammonia, nitrites, and nitrates from our aquarium, Purigen to promote healthy bacteria, and a little filter media to filter out the solid waste was the most cost-effective and time-efficient solution.

In addition, we installed an under gravel filter, to help keep any particulate matter from clouding the tank. The fish actually love these, swimming through the bubbles to get a little morning swim in before a hard day’s work. Don’t fight it, let nature automation in!

See For Yourself

We are so proud of how far we have come and how beautiful our aquarium is that we wanted to share it with the world. Please feel free to watch the live stream of our aquarium here: https://aquarium.prettybaked.com.

The Current Crew of the S.S. Aquarium

Using Nature Automation, happy aquarium fish swim through a thriving ecosystem.

Fan Tailed Guppies

Neon Blue Guppy: Tropical Fish for Freshwater Aquariums
Blue/Green Fan Tail Guppy
Orange/Red Fan Tail Guppy

Cory Catfish

Bandit Cory
Spotted Cory

Gourami

Opaline Gourami
Marbled Gourami
Dwarf Flame Gourami
Pearl Gourami
Dwarf Sunset Gourami

Sharks

Rainbow Shark

Algae Eaters

Siamese Algae Eater

To Be or Not ecobee…

There’s no question here

To the uninitiated, the ecobee is a cloud-first smart thermostat that utilizes remote sensors to attempt to optimize your home’s temperature based on room occupancy. A novel idea, especially if your thermostat is located near warm windows or the front door like ours, but I believe we can do a whole lot better!

Taking a Look at Ecobee

First, let’s discuss the initial cost you will incur before you even get the system installed. These things are fairly pricey – around $250 for the thermostat and one sensor – and it gets more expensive if you have a lot of rooms. Assuming you want sensors in your bedroom, living room, office, kids’ rooms, dining room and family room, you’re looking at $500 to ensure comfort in any room of your home.

Alright, you just dropped a good chunk of change on your brand new smart climate control, time to install it! Do you have an older home like we do? You’re HVAC system probably does not include a C-wire – not to worry, the system comes with a power-extender kit, which only requires a little rewiring inside your furnace control panel. Assuming you haven’t electrocuted yourself, the main unit is now mounted on the wall where your old thermostat was – unless you decided to go all-out and run wires to a new more optimum location (hope you have some fish tape…).

You’re not done yet, it’s time to place the remote sensors around your house. Make sure to choose locations such that the sensor can see the room, won’t be artificially affected by sun through windows and, most importantly, receive fairly consistent motion when the room is occupied. Why? Well, unlike occupancy sensors – which can detect if a person is in the room regardless of motion, these remote sensors rely on a motion-timeout mechanism; basically, if the sensor will only report occupancy if it detects motion within a certain timeframe. You might want to rethink putting that sensor where you primarily watch movies or television, if your comfort settings are not set correctly, 2 hours into your 15th viewing of Avatar it may just switch to away mode.

Finally, your system is installed, set up and keeping your house comfortable – but this wouldn’t be a very smart thermostat if it didn’t prepare your home for optimum comfort on your way home, now would it? Well, it’s a good thing the companion app utilizes geofencing to preemptively switch to home mode on your way back from 4 hour trip to IKEA! Let’s just hope you live alone or always travel with your family, since this feature is limited to one user without the help of 3rd party applications like Life,360 or AFAIK.

If a Company like Ecobee Has These Issues, What Can I Do?

Problem 1: Cost

This is an easy one, go to Amazon and look for a thermostat that integrates with your home’s smart protocols – Zigbee, Z-Wave, Thread/Bluetooth, Wi-Fi – you’ll find thousands of options. Make sure to read the reviews and find a quality thermostat, we have a GoControl GC-TBZ48 which I found on Amazon a few years ago for around $115 but seems to run about $150 now. Don’t forget eBay, you can find used or near-new units even cheaper.

Problem 2: Installation/No C-Wire

If you have no C-Wire, there are plenty of battery-powered options to avoid scary electrical work out there as well. The unit linked above can operate off of the 24VAC transformer in your furnace, as well as the 6V provided by 4 AA batteries included with the unit.

Problem 3: Remote Sensor Cost

Like Problem 1, you’ll find a plethora of options for temperature and motion sensors for whatever protocols your home uses on Amazon. If you have a lot of Philips Hue products, the Hue Motion Sensor provides motion and temperature readings and can be found cheap on eBay. If your protocol of choice is Z-Wave, I recommend Aeotec make reliable devices that are highly configurable, including 3 and 6 sensor devices – however, they cost about as much as the ecobee remote sensors, so check out Monoprice for white-label Z-Wave devices to save some cash. If you look around, you’ll find a decent device that fits your price point.

Problem 4: Lack of Motion

Unfortunately, there’s no universal solution to solving the lack of motion issue; there are, however, plenty of DIY solutions. A simple solution: the Aeotec sensors have configurable sensitivity, reporting thresholds, alert timeout and motion time out settings – adjusting these can virtually eliminate the lack of motion issue. Serious DIYers might look into using Time-of-Flight sensors to keep track of people entering and exiting a room, similar to this Instructables project. For a fool-proof method, some cheap webcams, or even Raspberry Pi 0 Ws with camera modules, and TensorFlow or OpenCV can literally detect people and faces if you don’t mind installing cameras around your house – and facilitate a future project I’d like to take on to pause/play the movie based on the number of faces/people changing in the room.

Problem 5: Geofencing

The single-user geofencing “feature” of ecobee is a non-issue to most home automators. I’m going to assume you either have GPS tracking set up if not, checkout Home-Assistant + Companion Mobile App with zones and proximity, it’s fairly user friendly and has most of this built in.

Let’s See How a We Can Do Better

Following Agile practices, let’s create some feature stories, a feature story usually includes a title, statement of intent, acceptance criteria list and possibly stretch goals. Below are some cards describing the features I would like to implement in our comfort system

Comfort on Demand

As a smart-home owner
I would like the house to be comfortable when I get home
so that I do not have to wait be comfortable

Acceptance Criteria

  • Home mode is set when a family member is within a certain radius from home and traveling towards home
  • Do nothing if someone is home and climate is set to home mode
  • Return climate to away mode if family member leaves the radius or travels away from home

Stretch Goal ACs

  • Set home mode based one calendar event end time and ETA from event to home

Sensor Calibration

As a smart-home owner
I would like to adjust the sensor readings for calibration or offset
so that temperature readings are reliable

Acceptance Criteria

  • Sensor readings are offset by a specified calibration value

Stretch Goal ACs

  • Adjust offset based on sun or detected light levels

Room Priority Ranking

As a smart-home owner
I would like areas to be ranked by traffic levels
so that high-traffic areas have a greater impact than low-traffic areas

Acceptance Criteria

  • Sensors have a base weight used for averaging
  • Sensors have an adjusted weight when an area is triggered for averaging

Stretch Goal ACs

  • Adjust weights based on historical traffic data

Personalized Comfort

As a smart-home owner
I would like the climate adjust based on the preferences of guests
so that my guests are more comfortable

Acceptance Criteria

  • Guests can specify a preferred temperature or fan settings
  • Climate adjusts when a guest with preferred climate settings arrives
  • Climate reverts back when guest with preferred climate settings departs

Stretch Goal ACs

  • When multiple preferred climate guests are present, climate adjustments are averaged if needed

Climate on Demand

You may have guessed, but we run Home-Assistant, amongst other projects, in our home. Robbie Trencheny created a wonderful mobile application for iOS that has grown and been forked for Android systems. Using some of the native integrations we can easily create a ruleset to achieve our goal of arriving home to a comfortable client.

To follow in our footsteps, you’ll need to have Home-Assistant setup and running with the following integrations configured:

  • mobile_app – This allows the Companion Mobile App to communicate with the Home-Assistant server
  • person – Create a person entity for each person you which to track and tie it to the device_tracker added via mobile_app with succinct names like “Dad” or “Mom”
  • zone – You will want to set up a “Thermostat” zone with a decent radius to act as the threshold for determining if a user is heading home or not
  • proximity – Set up a proxy entity for each person you wish to determine the proximity to zone.home, using a naming convention such as “Home Dad” or “Home Mom”
  • group – Create a group entity that contains all of the person entities above
  • climate – The appropriate integration for your smart thermostat

Here is a very basic example configuration file to get you going, add the appropriate configuration for your thermostat for your home:

## configuration.yaml
...

mobile_app:

person:
  - name: Dad
    id: dad123
    device_trackers:
      - device_tracker.dad
  - name: Mom
    id: mom321
    device_trackers:
      - device_tracker.mom

group:
  family:
    name: Family
    entities:
      - person.dad
      - person.mom

zone:
  - name: Thermostat
    latitude: !secret latitude_home
    longitude: !secret longitude_home
    radius: 1700  # Just over a mile
    icon: mdi:thermostat

proximity:
  home_dad:
    zone: home
    devices:
      - person.dad
    tolerance: 50
    unit_of_measurement: mi
  home_mom:
    zone: home
    devices:
      - person.mom
    tolerance: 50
    unit_of_measurement: mi
    
automation: !include_dir_list automations
# automations/prepare_climate_home.yaml
# This assumes your thermostat supports preset modes, if not adjust service call appropriately, i.e. climate.set_temperature
name: Prepare Climate Home Mode
trigger:
# Trigger automation when Mom or Dad enter the Thermostat Zone
  - platform: zone
    entity_id:
      - person.mom
      - person.dad
    zone: zone.thermostat
    event: enter
condition:
# Only run automation if no one is home and the person that triggered the 
# automation is heading towards from Home
  - condition: not
    conditions:
      - condition: state
        entity_id: group.family
        state: home
  - condition: template
    value_template: "{{ is_state_attr('proximity.home_' + (states.person | selectattr('entity_id', 'eq', trigger.entity_id) | map(attribute='entity_id') | map('replace', 'person.', '') | list | first), 'dir_of_travel', 'towards') }}"
  - condition: state
    entity_id: "{{ trigger.entity_id }}"
    state: "Thermostat"
action:
# Set the thermostat to home mode
  - service: climate.set_preset_mode
    data:
      entity_id: climate.thermostat
      preset_mode: home
# automations/prepare_climate_away.yaml
# This assumes your thermostat supports preset modes, if not adjust service call appropriately, i.e. climate.set_temperature
name: Prepare Climate Away Mode
trigger:
# Trigger automation when Mom or Dad leave the Thermostat Zone
  - platform: zone
    entity_id:
      - person.mom
      - person.dad
    zone: zone.thermostat
    event: leave
condition:
# Only run automation if no one is home and the person that triggered the 
# automation is heading away from Home
  - condition: state
    entity_id: group.family
    state: home
  - condition: template
    value_template: "{{ is_state_attr('proximity.home_' + (states.person | selectattr('entity_id', 'eq', trigger.entity_id) | map(attribute='entity_id') | map('replace', 'person.', '') | list | first), 'dir_of_travel', 'away_from') }}"
  - condition: state
    entity_id: "{{ trigger.entity_id }}"
    state: "not_home"
action:
# Set the thermostat to away mode
  - service: climate.set_preset_mode
    data:
      entity_id: climate.thermostat
      preset_mode: away

Summarizing the Configuration Above

The first automation will set the home mode if a user enters the Thermostat radius and direction of travel is towards home, as long as no one is home already.

The second automation will set the away mode if a user leaves the Thermostat radius and direction of travel is away from home, as long as no one is home still.

Definition of Done

  • ✓ : Home mode is set when a family member is within a certain radius from home and traveling towards home
  • ✓ : Do nothing if someone is home and climate is set to home mode
  • ✓ : Return climate to away mode if family member leaves the radius or travels away from home

Sensor Calibration

# sensors/temperature_calibrations
sensor:
  - platform: template
    # Creates a sensor that is always 1 degree lower than what the kitchen temperature report
    kitchen_calibrated_temperature:
       name: Calibrated Kitchen Temperature
       value_template: "{{ (states.sensor.kitchen_temperature.state | int) - 1 }}
       icon: mdi:thermometer
       unit_of_measurement: "\u2109"
       device_class: temperature
   ...

Summarizing the Configuration Above

By utilizing the template sensor, you are able to apply any transformation to the reported sensor values you wish. In the example above, it is creating a new sensor that will always be 1 degree lower than the device’s reported temperature.

Definition of Done

  • ✓ : Sensor readings are offset by a specified calibration value

Room/Area Ranked Priority

Using a simple weighted-average algorithm fulfills this requirement. Each room or temperature sensor can have a default weight, as wells a triggered weight; the triggered weight will be used when the occupancy/motion sensor associated with this temperature reading detects motion. You can accomplish this with the Template Sensor integration, or you can utilize something like AppDaemon and use Python to calculate this.

# sensors/temperature_ranking
platform: template
sensors:
  thermostat_internal_offset:
     name: Thermostat Internal Offset
     value_template: "{{ climate.thermostat.attributes.offset }}"
     icon: mdi:thermometer-plus
     unit_of_measurement: "\u2109"
     device_class: temperature
  thermostat_actual_temperature:
     name: Thermostat Internal Offset
     value_template: "{{ (states('sensor.thermostat_temperature') | float) - (states('sensor.thermostat_internal_offset') | float) }}"
     icon: mdi:thermometer-lines
     unit_of_measurement: "\u2109"
     device_class: temperature
  average_temperature:
   name: Average Home Temperature
   value_template: |
     {%- set weights = 
       {
         "sensor.kitchen_temperature": {
           "weight": 0.8
           "triggered_weight": 1.2
           "triggered_by: {
             "entity_id": "binary_sensor.kitchen_motion"
             "state": "on"
           }
         },
         "sensor.living_room_temperature: {
           "weight": 1.0,
           "triggered_weight": 2.1
           "triggered_by: {
             "entity_id": "binary_sensor.living_room_motion"
             "state": "on"
           }
         },
         ... # Add all sensors and their weight data here
       } -%}
       {%- set ns = namespace(temperature=0.0, total_weight=0.0) -%}
       {%- for sensor, weight_data in weights.items() -%}
         {%- if 'triggered_weight' in weight_data and 'triggered_by' in weight_data and is_state(weight_data['triggered_by']['entity_id'], weight_data['triggered_by']['state'])  -%}
           {%- set ns.temperature = ns.temperature + (states(sensor) | float) * (weight_data['triggered_weight'] | float) -%}
           {%- set ns.total_weight = ns.total_weight + (weight_data['triggered_weight'] | float) -%}
         {%- else -%}
           {%- set ns.temperature = ns.temperature + (states(sensor) | float) * (weight_data['weight'] | float) -%}
           {%- set ns.total_weight = ns.total_weight + (weight_data['weight'] | float) -%}
         {%- endif -%}
       {%- endfor -%}
       {{ None if ns.total_weight == 0.0 else (ns.temperature / ns.total_weight) }}
     icon: mdi:thermometer
     unit_of_measurement: "\u2109"
     device_class: temperature
# automations/thermostat_offset.yaml
name: Set Thermostat Internal Offset
trigger:
  - platform: state
    entity_id: sensor.average_temperature
action:
  - service: mqtt.publish
    data:
      topic: "OpenZWave/1/command/setvalue/"
      payload_template: '{ "ValueIDKey": 12345, "Value": {{ ((states('sensor.average_temperature') | float )
                               - (states('sensor.thermostat_actual_temperature') | float)) | round('half') }} }'

Summarizing the Configuration Above

First, we define some Template Sensors to facilitate the arithmetic and automations that follow. Since our automation will adjust the internal offset of the thermostat so that the reported temperature of the thermostat is actually the weighted average temperature, we need to know what the “actual” thermostat temperature is without the offset applied and, for ease of use, what the thermostat’s current offset is. Now that we have these two sensors (sensor.thermostat_internal_offset, sensor.thermostat_actual_temperature), we can use the values of these entities to calculate what the offset should be every time the average temperature sensor changes. Now, it doesn’t really matter where in your house the thermostat is mounted, because the temperature it’s reporting is ignored and, effectively, replaced with what we have calculated to be the temperature in the house based on occupancy and weights (or “rank” if you prefer).

Definition of Done

  • ✓ : Sensors have a base weight used for averaging
  • ✓ : Sensors have an adjusted weight when an area is triggered for averaging

Personalized Comfort

If you are like us, you want your friends and guests to be comfortable in your home – or maybe your significant other prefers the house a little cooler than you do. Personalized comfort allows you to accommodate some of the common requests you may receive, such as:

  • “I run hot, can we kick the AC up a bit?”
  • “It’s stuffy in here, is it ok if I turn on the fan?”
  • “I prefer natural light, would you mind if I opened the blinds?”
# customization.yaml
person.bob:
  target_temp: 72
person.jim
  fan_speed: low
person.annie
  window_coverings: open
# automations/personal_comfort.yaml
name: Personal Comfort Settings
trigger:
  - platform: state
    entity_id:
      - person.bob
      - person.jim
      - person.annie
action:
  - choose:
    - conditions:
      - condition: template
        value_template: >-
          {{ state_attr(trigger.entity_id, "target_temp") != None }}
        sequence:
          - service: climate.set_temperature
            data:
              entity_id: climate.thermostat
              temperature: "{{ (states.input_number.target_temperature.state | int) if is_state(trigger.entity_id, "not_home") else (state_attr(trigger.entity_id, "target_temp") | int) }}"
    - condition: template
        value_template: >-
          {{ state_attr(trigger.entity_id, "fan_speed") != None }}
        sequence:
          - service: fan.set_speed
            data:
              entity_id:
                - fan.living_room
                - fan.guest_room
              # Not bothering to reset when they leave
              speed: "{{ state_attr(trigger.entity_id, "fan_speed") | int }}"
    - condition: template
        value_template: >-
          {{ state_attr(trigger.entity_id, "window_coverings") != None }}
        sequence:
          - service: "cover.{{ 'close' if is_state(trigger.entity_id, 'not_home') else state_attr(trigger.entity_id, "window_coverings") }}_cover
            data:
              entity_id:
                - cover.living_room_blinds
                - cover.family_room_blinds
    default: []

Summarizing the Configuration Above

The example presented is fairly basic, covering only one preference per person. If the guest has a temperature preference it will adjust the thermostat, if the guest has a preference on air circulation it will adjust the specified fans to meet their request, if they have a preference for the blinds to be open it will open the specified blinds. When they leave, it returns to original state.

Definition of Done

  • ✓ : Guests can specify a preferred temperature or fan settings
  • ✓ : Climate adjusts when a guest with preferred climate settings arrives
  • ✓ : Climate reverts back when guest with preferred climate settings departs

Stretch Goals

If you like the ideas presented in the cards above under stretch goals, or can think of other improvements over the ecobee, I challenge you to implement your solution and share it with the world!

Let There Be Light! Comfort Color Lighting…

As you read through this post, watch the videos, see what all we’ve done – it’s only natural to ask “Jeez, how much did this cost?” Well, let me answer that now so we can focus on the content: you do not want to know. Links below seem to break on the regular, find the videos and more here: https://www.icloud.com/sharedalbum/#B1A59UlCq1m3Dr

HEADS UP: If you use “Hey Siri” in your home, you may want to turn the volume down before playing the videos below, and on a personal note: James, fuck you and your phrases used in https://saladbowl.fun

Introducing: Comfort Color Lighting, Automated

As you know, or should by now, I put a lot of pride into being efficiently lazy: automating repetitive tasks, communication, and my life to an extent some might consider insane (I prefer eccentric, potato-potato). About a year ago, my partner/boyfriend/fiancé, let’s call him Alan, and I stayed a weekend at our good friend’s who recently started adding Philips Hue lighting to his house; this weekend with friends sparked something deep in Alan’s soul, turning to me “I need this in my life” – and thus began our journey to not just be more comfortable in our home, but to turn our home into our sanctuary, into an immersive experience of unto which we could not have imagined possible at the time.

I’ll be the first to admit, I never really thought much of color – sure I have a preference for dark themed user interfaces just like any sane software engineer, selecting the “Darcula” radio button is enough for me; automating my lights simply meant replacing the light switches with smart ones. When I introduced Alan to Pycharm as an alternative to Sublime, he was blown away by the Ansible/YAML plugins and extensions that he instantly dropped Sublime as his editor of choice – and spent the next day or two tweaking the color schemes, asking my opinion between two indiscernible grays looked best as the editor background.

Side note, his need for perfect color schemes in his life seemed like a waste of time to me at first, but I have truly grown to appreciate how the varying tones in color can really affect you – I still can’t bring myself to spend the time to tweak my editor colors so I simply use the themes he lovingly creates from scratch.

Understanding Alan’s affinity for color and its effects on mood and focus, we can now appreciate the super-human patience and effort that he has put in; turning our house into a home, our living room into an immersive theatre better than any AMC or Alamo, and practically removing the need for an alarm to wake up in the morning – all through the use of comfort color lighting.

Energy, Mood and Adaptive Lighting

For the uninitiated, adaptive lighting is an algorithm that brings the awe of the sun rising, the beauty of a wonderful setting sun, the tranquility of a clear night sky into your home through the color and temperature of lights in your home. As the day starts, gentle and beautiful sunrises throughout our home – slowly transitioning from a comfortable, yet dim, twilight to a beautiful sky blue and hints of orange – awakened every day to the artificially created beauty of nature, regardless of what the weather is outside these walls. As the day rolls on, and the sun starts to set, the sky blue darkens, the hints of orange now prominent, the tint of red as the sun’s rays pass over the atmospheric scattering effect so prominent during the day. Soon, below the horizon, twilight starts to set in – the sky a dark backdrop sprinkled with fuchsia from the few photon particles that pass tangentially over our planet as the sun sinks deeper and deeper. With gratitude for his lighting work, I rarely wake In the mornings grumbling anymore, instead, the comfort color lighting makes me feel inspired and energized – though that still doesn’t seem to curb my intake of caffeine, that’s a whole other thing.

Time of Day Comfort Lighting Scenes

Enter Your Favorite Movie, No VR Headset Required

We all seem to have that person in our life: the self-proclaimed audiophile who can’t stand for anything less than 7.2 Atmos surround, the purist nitpicking digital artifacts due to compressed video streams, those who scoff at televisions that don’t upscale to the point of being able to see every pore on an actor’s face. Well, we are those people, and then some. Before the world shut down in response to an invasion from microscopic organisms hell-bent on world domination, most people went to movie theaters to get a taste of immersive sound and visuals – and spend $10 on a bag of Skittles. Let me introduce you to the Philips Hue Sync Box, one of the most amazing devices to enter the home entertainment market, and one of the worst smart devices ever made. When it comes to being a smart device, it’s the equivalent of the most intelligent goldfish at Petsmart – the app is slow, has wireless connection issues and requires a dedicated Hue Hub for each Sync Box in your home. Thankfully, the REST API served on the device is responsive and intuitive – a great addition to your home automation system. If it’s one of the worst smart devices ever made, how can it be such an amazing home entertainment device? Good question. Simply wire your set-top boxes to any of the 4 HDMI inputs on the Sync Box and the output to your stereo or television – and now up to 10 Hue (or Hue Compatible) lights synchronize with the image displayed on your television, or create a visualizer for music. Not long ago, the light strips by Philips Hue could only be set to one color for the whole strip – but now you can get a Gradient Light Strip sized for your television…. words cannot compete with seeing it in action:

Video Mode with Mad Max
Fury Road Dust Storm Battle
Video Mode with Rango
Crossing the Road with Rango
Video Mode with Music and Visualizer
This is the Game Room with a Hue Play Gradient Light Strip
Music Mode with Music
Opiuo canceled their 2020 show, experience it in your living room

Setting the Mood

Check back later for mood lighting and scenes!

But Wait, There’s More!

Here’s the lighting we use around our house

  • Living Room
    • TV Backlight: Hue Gradient Light Strip
    • Under TV: Hue Light Strip
    • Couch Light: Hue Light Strip + Extension
    • Behind Speakers: Hue Play Bars
    • Ceiling Fan: Hue Ambiance Bulbs
  • Game Room
    • TV Backlight: Hue Gradient Light Strip
    • Closet: Hue Light Strip + Extension
    • Ceiling Light: Insteon On/Off Switch
  • Entry Room
    • Mantel: Hue Light Strip
    • Floor Lamp: Hue Color Bulbs
  • Kitchen
    • Hall Light: Hue Play Bar
    • Ceiling Light: Insteon On/Off Switch
  • Dining Room
    • Ceiling Fan: Hue Ambiance Bulbs
  • Hallways:
    • Ceiling Light: Hue Being Ambiance Fixture
  • Bathrooms:
    • Vanity: Hue Ambiance Bulbs
    • Ceiling: Hue Ambiance Bulbs
  • Bedroom
    • TV Accents: Hue Play Bars
    • Headboard Accents: Hue Play Bars
    • Ceiling Fan: Hue Ambiance Bulbs
  • Dance Studio
    • Nanoleaf Panels
  • Exterior
    • Wall Sconces: Hue Appear Ambiance Fixtures
    • Walkway: Hue Calla Ambiance Fixtures

Keep up to date as we add lighting, scenes, and effects to our home: https://www.icloud.com/sharedalbum/#B1A59UlCq1m3Dr