I've barely toyed with SwiftUI, but has gotten me thinking about declarative languages, and I'd like to try to make a home automation language as a Swift-based DSL. Thing is, I don't really know how Swift does its magic, with the bindings and such. But I think that's what I need.
I spent the last half-hour just spitballing some potential language constructs, and I've gotten something that sort-of compiles (but is nowhere near being an operable product). But the last little bit I've run into is, I think, where I'd want some sort of binding.
There may not be enough here to understand what I'm driving at, but maybe there is. Imagine defining a set of rules like this:
// Create devices so we can set up rules for them.
// Some switches that can be turned on or off, and queried for their current on/off state…
let overheadLights = Device(serviceID: "urn:upnp-org:serviceId:SwitchPower1", number: 5)
let deskLight = Device(serviceID: "urn:upnp-org:serviceId:SwitchPower1", number: 34)
let waterHeater = Device(serviceID: "urn:upnp-org:serviceId:SwitchPower1", number: 25)
// We want a lot of our rules to depend on whether or not someone is present.
// This defines occupancy by whether or not the overhead lights are on. An
// alternative occupancy might be "Rick’s iPhone is present."
let occupied = overheadLights.on
// Schedule periods can be defined…
let summer = June...September
let winter = October...May
let onPeak = summer.weekdays(1600...2100)
let midPeak = summer.weekends(1600...2100) || winter.daily(1600...2100)
let offPeak = summer.weekdays(2100...1600) || winter.daily(2100...0800)
let superOffPeak = winter.daily(0800...1600)
// Create a rule that turns on the water heater any time the place is
// occupied, except during peak electricity rate ToU periods…
waterHeater.on = occupied && !onPeak // This is probably a binding, no?
The result of executing this swift code once should be to set up some internal data structures that the controller code can then use to keep all the devices in sync according to the rules. A quick stab at making that code compile looks like this. Note that Daily
will probably be some kind of data structure that holds a set of periods of time.
struct
TimeOfYear
{
let month : Int?
let day : Int?
let hour : Int?
let minute : Int?
let second : Int?
init(month: Int? = nil, day: Int? = nil, hour: Int? = nil, minute: Int? = nil, second: Int? = nil)
{
self.month = month
self.day = day
self.hour = hour
self.minute = minute
self.second = second
}
}
extension
TimeOfYear : Comparable
{
static
func < (lhs: TimeOfYear, rhs: TimeOfYear)
-> Bool
{
return true
}
}
struct
Period
{
let start : TimeOfYear
let end : TimeOfYear
}
let January = TimeOfYear(month: 1)
let February = TimeOfYear(month: 2)
let May = TimeOfYear(month: 5)
let June = TimeOfYear(month: 6)
let September = TimeOfYear(month: 9)
let October = TimeOfYear(month: 10)
let foo = June...September
struct
Device
{
init(serviceID inServiceID: String, number inNumber: Int)
{
}
var on : Bool
}
struct
Daily
{
func
weekdays(_ timeRange: ClosedRange<Int>)
-> Daily
{
return Daily()
}
func
weekends(_ timeRange: ClosedRange<Int>)
-> Daily
{
return Daily()
}
func
daily(_ timeRange: ClosedRange<Int>)
-> Daily
{
return Daily()
}
}
func
||(lhs: Daily, rhs: Daily)
-> Daily
{
}
func
...(lhs: TimeOfYear, rhs: TimeOfYear)
-> Daily
{
}
This declarative approach to home automation should bring the same benefits that it does to wiring up UI elements. Any advice or suggestions for how to make the rule implementation “really nice,” even at the expense of complex support infrastructure, would be much appreciated.
Thanks!