Store Monitoring Project Scripts
Here is a Listing of all the Scripts from the Store Monitoring Project.
To create your own system, copy the following Scripts into files with the names given with each Script. The top level "Scripts" directory is contained within your Virtual Wiring installation. See the Creating Scripts section section for details about creating Scripts in the Scripts directory.
Customization
You can adjust the temperature settings for each freezer individually (see the temperature settings file). You can also adjust the length of time a freezer can be out of range before setting an alarm (see startup file).
All alarms are sent to one or more email or text message addresses. The email/text message addresses are defined in the email addresses file.
Anytime you change your settings, restart the system (see the Scripts Restart section). For complete details on the system, see www.catalinacomputing.com.
Requesting Status
You can interact with the system using email or texting. Emailing/texting a message with the command:
status
will return the temperature of all the freezers and the state of the water sensor. Emailing/texting the command:
alarm status
will return the state of the alarms (which ones are active and which are not).
Listings
There are a total of 8 Scripts, grouped into the following sections:
Top Level Script
Scripts/user/store/startup.script
# This Script is called at startup time.
# You may want to change to top few sections of this file from time to time.
# Define times (in seconds) freezers can be out of range
F1Delay = 30 # Freezer1
F2Delay = 300 # Freezer2
F3Delay = 300 # Freezer3
F4Delay = 300 # Freezer4
F5Delay = 0 # Freezer5
# Set how often we want email messages sent when there's an alarm (in seconds)
AlarmEmailInterval = 600 # 10 minutes
# Set up gmail account - sends and receives messages.
GMAIL_USER = "my_account@gmail.com"
GMAIL_PASSWD = "my_account_password"
# The lines below here probably won't need to change, once things are running.
# Name freezers 1-5
FID1 = "freezer1"
FID2 = "freezer2"
FID3 = "freezer3"
FID4 = "freezer4"
FID5 = "freezer5"
# Name status device
Status = "a_status" # make show at top
# Name the settings device
Settings = "b_temp_settings"
# Name the alarm device
Alarm = "c_alarm"
# Name the Power Loss sensor signal
PowerLoss = "power_loss"
# Name the pulser for the power signal
PowerLossPulser = "power_pulser"
# Name the motion sensor signal
Motion = "motion"
# Name the wet basement signal
WetBasement = "wet"
# Name the pulser for the wet basement signal
WetBasementPulser = "wet_pulser"
# define the port where our IO8 lives
optional_script_parameters(port:"/dev/ttyUSB0")
# create the device with our temperature settings
run_script("Scripts/Device/Virtual/StateMachine", id:Settings, file_name:"Scripts/user/store/temp_settings.yaml")
# set up IO8 - provides temperature and water sensor inputs
run_script("Scripts/Device/DLP/IO8", id:"io8", port_location:port)
run_script("", text:"write \"90-=OHJK\"", on_device:"io8") # 1-5 temp, 6-8 digital input
# set up the temperature sensing systems
run_script("Scripts/user/store/temp_checker.script", delay:F1Delay, id:FID1)
run_script("Scripts/user/store/temp_checker.script", delay:F2Delay, id:FID2)
run_script("Scripts/user/store/temp_checker.script", delay:F3Delay, id:FID3)
run_script("Scripts/user/store/temp_checker.script", delay:F4Delay, id:FID4)
run_script("Scripts/user/store/temp_checker.script", delay:F5Delay, id:FID5)
# create an alarm device
run_script("Scripts/Device/Virtual/Alarm/Alarm", duration:10, id:Alarm)
# define its alarm inputs
run_script("Scripts/Device/Virtual/Alarm/InputTypes/Equal", alarm_id:Alarm, input_name:"#{FID1}", value:"on")
run_script("Scripts/Device/Virtual/Alarm/InputTypes/Equal", alarm_id:Alarm, input_name:"#{FID2}", value:"on")
run_script("Scripts/Device/Virtual/Alarm/InputTypes/Equal", alarm_id:Alarm, input_name:"#{FID3}", value:"on")
run_script("Scripts/Device/Virtual/Alarm/InputTypes/Equal", alarm_id:Alarm, input_name:"#{FID4}", value:"on")
run_script("Scripts/Device/Virtual/Alarm/InputTypes/Equal", alarm_id:Alarm, input_name:"#{FID5}", value:"on")
run_script("Scripts/Device/Virtual/Alarm/InputTypes/Equal", alarm_id:Alarm, input_name:"#{PowerLoss}", value:"on")
run_script("Scripts/Device/Virtual/Alarm/InputTypes/Equal", alarm_id:Alarm, input_name:"#{Motion}", value:"on")
run_script("Scripts/Device/Virtual/Alarm/InputTypes/Equal", alarm_id:Alarm, input_name:"#{WetBasement}", value:"on")
# create a text messaging device
run_script("Scripts/Device/EMail/WiredMessagingPOP", gmail_polling:true, host:"pop.gmail.com", id:"emailer", inputs:"alarm_message, sys_status", mail_subject:"R2BC Alarm System", outputs:"status, alarm", password:GMAIL_PASSWD, poll_interval:480, smtp_host:"smtp.gmail.com", smtp_port:587, ssl_enable:true, user_name:GMAIL_USER)
# set up destination email and text addresses:
run_script("Scripts/Device/EMail/addEmailAddress", file_name:"Scripts/user/store/email_addresses.yaml", email_device_id:"emailer")
# create a status device - shows temperature and water sensor status
run_script("Scripts/Device/Virtual/Status", id:"#{Status}", inputs:"#{FID1}, #{FID2}, #{FID3}, #{FID4}, #{FID5}, #{PowerLoss}, #{Motion}, #{WetBasement}")
# Create a timer for creating regular messages, so we know system is OK
run_script("Scripts/user/store/message_timer.script")
# Create a pulser that pulses the WetBasement signal when it's active.
# Causes regular emails to be sent, when there's an alarm.
run_script("Scripts/user/store/pulsed_input.script", id:WetBasementPulser, pulse_duration:AlarmEmailInterval)
# Create a pulser that pulses the PowerLoss signal when it's active.
# Causes regular emails to be sent, when there's an alarm.
run_script("Scripts/user/store/pulsed_input.script", id:PowerLossPulser, pulse_duration:AlarmEmailInterval)
# Wire things together
# wire messaging device in
wire("#{Alarm}:messages", "emailer:alarm_message")
wire("emailer:alarm", "#{Alarm}:command")
wire("#{Status}:out", "emailer:sys_status")
wire("emailer:status", "#{Status}:in")
# wire the IO8 sense outputs to our devices
wire("io8:1S", "#{FID1}:temp")
wire("io8:2S", "#{FID2}:temp")
wire("io8:3S", "#{FID3}:temp")
wire("io8:4S", "#{FID4}:temp")
wire("io8:5S", "#{FID5}:temp")
wire("io8:6S", "#{PowerLossPulser}:input")
wire("#{PowerLossPulser}:output", "#{Alarm}:#{PowerLoss}")
#wire("io8:7S", "#{Alarm}:#{Motion}")
wire("io8:8S", "#{WetBasementPulser}:input")
wire("#{WetBasementPulser}:output", "#{Alarm}:#{WetBasement}")
# wire water and temperature values to status device
wire("io8:1S", "#{Status}:#{FID1}")
wire("io8:2S", "#{Status}:#{FID2}")
wire("io8:3S", "#{Status}:#{FID3}")
wire("io8:4S", "#{Status}:#{FID4}")
wire("io8:5S", "#{Status}:#{FID5}")
wire("io8:6S", "#{Status}:#{PowerLoss}")
#wire("io8:7S", "#{Status}:#{Motion}")
wire("io8:8S", "#{Status}:#{WetBasement}")
# wire temperature terminal block alerts to alarm device
#wire("#{FID1}:alert", "#{Alarm}:#{FID1}")
#wire("#{FID2}:alert", "#{Alarm}:#{FID2}")
#wire("#{FID3}:alert", "#{Alarm}:#{FID3}")
#wire("#{FID4}:alert", "#{Alarm}:#{FID4}")
#wire("#{FID5}:alert", "#{Alarm}:#{FID5}")
# wire settings block to temp sensor terminal blocks
wire("#{Settings}:f1_max", "#{FID1}:t_max")
wire("#{Settings}:f1_min", "#{FID1}:t_min")
wire("#{Settings}:f2_max", "#{FID2}:t_max")
wire("#{Settings}:f2_min", "#{FID2}:t_min")
wire("#{Settings}:f3_max", "#{FID3}:t_max")
wire("#{Settings}:f3_min", "#{FID3}:t_min")
wire("#{Settings}:f4_max", "#{FID4}:t_max")
wire("#{Settings}:f4_min", "#{FID4}:t_min")
wire("#{Settings}:f5_max", "#{FID5}:t_max")
wire("#{Settings}:f5_min", "#{FID5}:t_min")
# wire up our message timer so it generates messages
wire("message_event:out", "#{Status}:in")
Alert Recipients Script
Scripts/user/store/email_addresses.yaml
# Define email and texting addresses for the system
# To send to a text messaging device, use the email address of the device.
# For example, to send to Verizon device, one might use
# 6175551212@vtext.com, where the 10 digit string is a cell phone number
# and vtext.com is the cell phone email host of the provider.
# To find the host name for your wireless provider,
# look at wikipedia under: List of SMS gateways.
# Add all your email and text messaging addresses here.
# Separate addresses with a comma. For example:
# addresses: [
#
# person@company.com,
# person2@company.com,
# person3@company.com
#
# ]
addresses: [
# add your addresses here
]
Temperature Settings Script
This Script defines the acceptable temperature ranges for each of the 5 freezers. Temperatures are in Fahrenheit.
Scripts/user/store/temp_settings.yaml
# Freezer high and low temperature monitoring settings
# Change temperature values to match your needs.
settings:
-
Initialize:
# Freezer 1
f1_min: -10
f1_max: 20
# Freezer 2
f2_min: -10
f2_max: 20
# Freezer 3
f3_min: -10
f3_max: 20
# Freezer 4
f4_min: -10
f4_max: 20
# Freezer 5
f5_min: -10
f5_max: 20
Morning Status Timer Script
This Script builds a timer which causes a status message to be sent every morning at 8:00. It uses an EventGenerator Device to turn "on" events from the timer into triggers and to filter out "off" events. It filters out "off"s, so only one status message is sent per day.
Scripts/user/store/message_timer.script
# Create a timer which will generate events for sending messages.
# Create up our timer - 1 message every day at 8:00
run_script("Scripts/Device/Virtual/TimerInterval", days:"", id:"message_timer", intervals:"8:00 to 8:01", weekdays:"")
# Map off/on events from the timer to "message1", "message2" events, one per "on" event.
run_script("Scripts/Device/Virtual/EventGenerator", id:"message_event", triggers:"on", values:"message1, message2")
# Hook up the timer to the message output, so each timer "on" event, generates a message event.
wire("message_timer:out", "message_event:in")
Temperature Checking Scripts
There are 2 Scripts for temperature checking. The first builds a temperature checker, and the second is the state machine used by the checker.
Scripts/user/store/temp_checker.script
# Script which makes a temperature checker - you shouldn't need to modify this.
# Takes 2 parameters - "id" and "delay".
# The "id" is a prefix for all the device IDs and wires created by this script.
# The delay is the amount of time (in seconds) the temperature can be out of range
# before the checker sets an alert.
optional_script_parameters(id:"temp_checker", delay:300)
# Has 3 inputs and 1 output.
# The "t_max" and "t_min" inputs are the high an low values the temperature must lie within.
# The "temp" input is the current temperature.
# The "alert" output is "on" when the temperature has been out of range for the delay time.
# The "alert" output is "off" when it is not "on".
# Create our devices
# Create the (virtual) terminal block with our 3 inputs and 1 output.
run_script("Scripts/Device/Virtual/TerminalBlock", id:"#{id}", inputs:"temp, t_max, t_min", outputs:"alert")
# high and low check comparators
run_script("Scripts/Device/Virtual/Comparator", hysteresis:1, id:"#{id}_comp_hi")
run_script("Scripts/Device/Virtual/Comparator", hysteresis:1, id:"#{id}_comp_lo")
# one shot for timing
run_script("Scripts/Device/Virtual/Logic/Active/OneShot", duration:delay, id:"#{id}_one_shot")
# state machine for running the system
run_script("Scripts/Device/Virtual/StateSpace/StateSpace", id:"#{id}_sm")
run_script("Scripts/Device/Virtual/StateSpace/loadTablesFile", file_name:"Scripts/user/store/temp_checker.yaml", state_space_id:"#{id}_sm")
# two tables - one for the alert output and one for the two comparators
run_script("Scripts/Device/Virtual/StateSpace/StateMachine", comparator:"one_shot_clk", one_shot:"one_shot", out:"out", state_space_id:"#{id}_sm", table_name:"checker")
run_script("Scripts/Device/Virtual/StateSpace/StateMachine", clk:"one_shot_clk", hi:"hi", lo:"lo", state_space_id:"#{id}_sm", table_name:"one_shot_clk")
# wire things up
# terminal block
wire("#{id}:temp", "#{id}_comp_hi:plus")
wire("#{id}:temp", "#{id}_comp_lo:minus")
wire("#{id}:t_max", "#{id}_comp_hi:minus")
wire("#{id}:t_min", "#{id}_comp_lo:plus")
# state machine
wire("#{id}_comp_hi:out", "#{id}_sm:hi")
wire("#{id}_comp_lo:out", "#{id}_sm:lo")
wire("#{id}_sm:one_shot_clk", "#{id}_one_shot:clk")
wire("#{id}_one_shot:out", "#{id}_sm:one_shot")
wire("#{id}_sm:out", "#{id}:alert")
Scripts/user/store/temp_checker.yaml
# Temperature checker state machine - you shouldn't need to modify this.
"checker":
# things that turn the output off
-
When: {comparator: "off"}
State: {out: ["", "on"]}
Then: {out: "off"}
# Things that turn the output on
-
When: {one_shot: "off"}
State: {comparator: "on"} # both on for time interval
Then: {out: "on"}
# an OR circuit state machine
# run the one shot clock using the 2 comparator inputs
"one_shot_clk":
-
Initialize: {clk: "off"} # start clk low (for one-shot)
-
When: {hi: "on", lo: "on"}
Then: {clk: "on"}
-
When: {hi: "off", lo: "off"}
State: {hi: "off", lo: "off"}
Then: {clk: "off"}
Input Pulser Scripts
Creates an Input Pulser. Input Pulsers take an input in the "on" state and turn it into an output which pulses off briefly every "pulse_duration". When the input is off, the Input Pulser output stays off.
Pulsers cause our Alarms to be resent every pulse_duration, for as long is the alarm condition is active. Pulse duration is a number measured in seconds. Input Pulsers are built from a one-shot Device and a state machine.
Scripts/user/store/pulsed_input.script
# Pulse an input for an interval set by a one-shot.
# options for naming the devices uniquely, and the interval between pulses
optional_script_parameters(id:"input", pulse_duration:600) # default of 10 minutes
# create a state machine
run_script("Scripts/Device/Virtual/StateMachine", file_name:"Scripts/user/store/input_pulser.yaml", id:"#{id}", table_name:"")
# create a one-shot
run_script("Scripts/Device/Virtual/Logic/Active/OneShot", duration:pulse_duration, id:"#{id}_one_shot")
wire("#{id}_one_shot:out", "#{id}:one_shot_q")
wire("#{id}:one_shot_clock", "#{id}_one_shot:clk")
Scripts/user/store/input_pulser.yaml
# Create an output from an input, which pulses according to a one-shot interval.
"input_pulser":
-
Initialize: {one_shot_clock: "off"} # start clk low (for one-shot)
# when input changes, output follows
-
When: {input: "on"}
Then: {output: "on", one_shot_clock: "on"} # start timing
-
When: {input: "off"} # reset everything
Then: {output: "off"}
# once input is on, run the one shot and pulse the output
-
When: {one_shot_q: "off"}
State: {input: "on"}
Then: {output: "off", one_shot_clock: "on"} # pulse output and reset clock
-
When: {one_shot_q: "on"}
State: {input: "on"}
Then: {output: "on"} # pulse completed
# if clock goes high, reset it low - a pulse
-
When: {one_shot_clock: "on"}
Then: {one_shot_clock: "off"}
|
|