This week I built an app using an MVC framework. I used Active Record to handle the database, Sinatra to handle HTTP requests and responses, and Embedded Ruby (ERB) to render the views. The models and controllers are all written in Ruby.
The app is designed to allow users to monitor and measure energy use in their home (or place of work) by tracking how much each appliance in their home is used, then calculating its individual power consumption using that appliance’s manufacturer-listed wattage. The app allows users to group their appliances by room (kitchen, living room), or by category (lighting, climate control) with the ability to add appliances to multiple groups (kitchen+lighting or garage+power tools). Once all the appliances are entered into the database, users can see how much energy each group is using.
There are three main functional models that the app uses: Users, Groups, and Devices (Sinatra didn’t seem to like it when I named them ‘Appliances’ instead of ‘Devices’. At first, I imagined users entering Devices into the database, then grouping them after they had been created. I wanted Groups to have multiple Devices, and I wanted Devices to be able to have multiple Groups. It was clear that I would have to set up a many-to-many association for Groups and Devices. That left me with a decision about how Devices and Groups would be associated to Users. In order for Groups and Devices to both belong to a User, but also have many of each other, it would be best to have one belong to a user through the other, but which model takes precedence? Which model should be directly associated to a User, and which should be associated to the User through the other model?
My first approach was to associate the Devices directly to a User. I was thinking: “the app is designed to track Devices first and foremost and Groups are simply additional descriptors for individual Devices”. I continued with this pattern for a day or two but then started to run into some problems. Creating an empty Group and adding in Devices after they had been created was proving to be difficult. That’s because Groups needed at least one Device in order to be associated to a User. I didn’t like that flow, so I took a minute to draw out the associations. At first I drew out a tree to imagine my associations, then I drew a physical floor plan of a house. When I drew the house, the first thing I drew wasn’t the appliances, it was the rooms — so I started re-considering the association plan I had started out with. I redrew the tree with Groups being directly associated to the User and the flow of the app started to make more sense. I made a new branch on git and started switching up the associations.
Users would open the app and create Groups, then add Devices to those groups. Groups really only have one user-generated attribute — the name — which made it easy for Users to create Devices and Groups simultaneously, simply by entering a Group name for a Device upon creation (which also created a new Group with that name). I made an accompanying custom validation for Devices to ensure that they are created with at least one associated Group. The restructuring of the models and the database did take a while but was well worth it (and a good exercise in using git branches).
Devices have 3 user determined attributes that are used to calculate power consumption:
- Power — the manufacturer-listed wattage (in Watts)
- Standby — the wattage when the device is switched off, but plugged in (in Watts)
- Usage — how many hours per day the appliance is turned on (in hours)
The power consumption of each Device or Group is returned to the user in kW⦁h.
The power consumption formula the app uses is simple:
consumption = (power/1000)*usage + (standby/1000)*(24 — usage)
When I first formulated the idea for this app I saw one major limitation to the practical application of the technology — it relies on the user’s estimation of how many hours they use each device on an average day. After I wrestled with that perceived limitation for a while, I suddenly realized that the limitation actually helps to achieve the intended end-result of the app: to make users think about how much energy they use. In order to use the app effectively you have to pay attention to what appliances you are turning on and off, how often you are turning them on and off, and how long they stay on. When a user takes the time to gather and enter reliable data, that user will probably reduce their average daily energy consumption in the process.
Excited for the next project!