Skip to content

Instantly share code, notes, and snippets.

@dannyrandall
Created March 19, 2021 03:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dannyrandall/7cf61f155f931c86c6627539f8c1ef5d to your computer and use it in GitHub Desktop.
Save dannyrandall/7cf61f155f931c86c6627539f8c1ef5d to your computer and use it in GitHub Desktop.
ruleset manage_sensor {
meta {
name "Manage Sensor"
author "Daniel Randall"
use module io.picolabs.subscription alias subscription
shares sensors, temperatures, profiles, sensor_subs, temperature_reports
}
global {
rulesets = {
"io.picolabs.wovyn.emitter": {
"url": meta:rulesetConfig{["rulesets", "io.picolabs.wovyn.emitter", "url"]}.defaultsTo("")
},
"sensor_profile": {
"url": meta:rulesetConfig{["rulesets", "sensor_profile", "url"]}.defaultsTo("")
},
"wovyn_base": {
"url": meta:rulesetConfig{["rulesets", "wovyn_base", "url"]}.defaultsTo("")
},
"temperature_store": {
"url": meta:rulesetConfig{["rulesets", "temperature_store", "url"]}.defaultsTo("")
}
}
defaults = {
"threshold": meta:rulesetConfig{["defaults", "threshold"]}.defaultsTo(100),
"notification_to": meta:rulesetConfig{["defaults", "notification_to"]}.defaultsTo("")
}
sensors = function() {
ent:sensors.defaultsTo({})
}
sensor_subs = function() {
subscription:established("Tx_role", "sensor").map(function(v) {
v.get(["Tx"])
})
}
temperatures = function() {
sensor_subs().map(function(s) {
{}.put(s, ctx:query(s, "temperature_store", "temperatures").defaultsTo([]).reverse().head())
})
}
profiles = function() {
sensor_subs().map(function(s) {
{}.put(s, ctx:query(s, "sensor_profile", "profile").defaultsTo({}))
})
}
temperature_reports = function() {
ent:temperature_reports.defaultsTo({})
}
}
rule add_sensor {
select when sensor new_sensor
pre {
name = event:attrs{"name"}
duplicate = ent:sensors && ent:sensors >< name
}
if duplicate then
send_directive("error", {"error": "cannot create duplicate child"})
notfired {
raise wrangler event "new_child_request" attributes {
"name": name
}
}
}
rule sensor_added {
select when wrangler new_child_created
foreach rulesets setting(rule)
pre {
name = event:attrs{"name"}
eci = event:attrs{"eci"}
}
if name && eci then
event:send({
"eci": eci,
"domain": "wrangler",
"type": "install_ruleset_request",
"attrs": {
"url": rule{"url"},
"config": rule{"config"},
}
})
fired {
ent:sensors := ent:sensors.defaultsTo({}).put(name, eci) on final
raise sensor event "sensor_added" attributes {
"name": name
} on final
}
}
rule configure_sensor {
select when sensor sensor_added where event:attrs{"name"} && ent:sensors{event:attrs{"name"}}
pre {
name = event:attrs{"name"}
eci = ent:sensors{name}
}
event:send({
"eci": eci,
"domain": "sensor",
"type": "profile_updated",
"attrs": {
"name": name,
"temperature_threshold": defaults{"threshold"},
"notification_to": defaults{"notification_to"}
}
})
}
rule create_subscription {
select when sensor sensor_added where event:attrs{"name"} && ent:sensors{event:attrs{"name"}}
pre {
name = event:attrs{"name"}
eci = ent:sensors{name}
}
always {
raise wrangler event "subscription" attributes {
"name": name,
"wellKnown_Tx": eci,
"channel_type": "sensor_management",
"Rx_role": "sensor_manager",
"Tx_role": "sensor"
}
}
}
rule introduce_sensor {
select when sensor introduce
pre {
name = event:attrs{"name"}
eci = event:attrs{"eci"}
}
always {
raise wrangler event "subscription" attributes {
"name": name,
"wellKnown_Tx": eci,
"channel_type": "sensor_management",
"Rx_role": "sensor_manager",
"Tx_role": "sensor"
}
}
}
rule delete_all_sensors {
select when sensor delete_all_sensors
foreach ent:sensors setting(eci, name)
always {
raise wrangler event "child_deletion_request" attributes {
"eci": eci
}
clear ent:sensors{name}
}
}
rule delete_sensor {
select when sensor unneeded_sensor where event:attrs{"name"} && ent:sensors{event:attrs{"name"}}
pre {
name = event:attrs{"name"}
eci = ent:sensors{name}
}
always {
raise wrangler event "child_deletion_request" attributes {
"eci": eci
}
clear ent:sensors{name}
}
}
rule sub_sensor_threshold_violation {
select when sensor_manager sub_sensor_threshold_violation
always {
raise sensor_manager_profile event "send_sms" attributes {
"msg": "detected threshold violation at " + event:attrs{"timestamp"} + ". temperature: " + event:attrs{"temperature"}
}
}
}
rule start_temperature_report {
select when sensor_manager start_temperature_report
foreach sensor_subs() setting(eci)
pre {
reportID = event:attrs{"reportID"}
}
event:send({
"eci": eci,
"domain": "wovyn",
"type": "report_temperature",
"attrs": {
"reportID": reportID,
"sensorID": eci
}
})
always {
ent:temperature_reports := ent:temperature_reports.defaultsTo({}).put([reportID, "started"], time:now()) on final
ent:temperature_reports := ent:temperature_reports.defaultsTo({}).put([reportID, "total_sensors"], sensor_subs().length()) on final
}
}
rule collect_temperature_report {
select when sensor_manager temperature_report
pre {
sensorID = event:attrs{"sensorID"}
reportID = event:attrs{"reportID"}
temp = event:attrs{"temperature"}
reporting_sensors = ent:temperature_reports.defaultsTo({}).get([reportID, "reporting_sensors"]).defaultsTo(0)+1
total_sensors = ent:temperature_reports.defaultsTo({}).get([reportID, "total_sensors"])
}
if total_sensors && reporting_sensors >= total_sensors then
noop()
fired {
ent:temperature_reports := ent:temperature_reports.defaultsTo({}).put([reportID, "ended"], time:now())
} finally {
ent:temperature_reports := ent:temperature_reports.defaultsTo({}).put([reportID, "reporting_sensors"], reporting_sensors)
ent:temperature_reports := ent:temperature_reports.defaultsTo({}).put([reportID, "reports", sensorID], temp)
}
}
rule clear_temperature_reports {
select when manage_sensor clear_temperature_reports
always {
ent:temperature_reports := {}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment