Skip to content

Instantly share code, notes, and snippets.

@gersilex
Last active July 29, 2018 18:52
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gersilex/13f39b3419427b35636a to your computer and use it in GitHub Desktop.
Save gersilex/13f39b3419427b35636a to your computer and use it in GitHub Desktop.
mysensors-openhab-rules-elements
// NOTES //
// "senso_irf24" is my String item with the serial binding
// in MySensors terms this is called the "Serial Gateway"
//
// CONTRIBUTE: Feel free to fork, enhance, pull reqest
//
// SiLeX <gersilex@gmail.com>
//
//
// IMPORTS //////////////////////////////////////////////////////////////////////////////////////////////////////////
import org.openhab.core.library.types.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
import java.util.HashMap
import org.eclipse.xtext.xbase.lib.*
import org.openhab.core.items.*
// VARS /////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MySensors 1.5 ////////////////////////////////////////////////////////////////////////////////////////////////////
// MessageTypes //
val int M_PRESENTATION = 0 // Sent by a node when they present attached sensors. This is usually done in setup() at startup.
val int M_SET = 1 // This message is sent from or to a sensor when a sensor value should be updated
val int M_REQ = 2 // Requests a variable value (usually from an actuator destined for controller).
val int M_INTERNAL = 3 // This is a special internal message. See table below for the details
val int M_STREAM = 4 // Used for OTA firmware updates
// SubTypes for MessageType M_PRESENTATION //
// (Not used for now, as automatic configuration is not possible in OpenHAB 1.)
// val int S_DOOR = 0 // Door and window sensors
// val int S_MOTION = 1 // Motion sensors
// val int S_SMOKE = 2 // Smoke sensor
// val int S_LIGHT = 3 // Light Actuator (on/off)
// val int S_BINARY = 3 // Binary device (on/off), Alias for S_LIGHT
// val int S_DIMMER = 4 // Dimmable device of some kind
// val int S_COVER = 5 // Window covers or shades
// val int S_TEMP = 6 // Temperature sensor
// val int S_HUM = 7 // Humidity sensor
// val int S_BARO = 8 // Barometer sensor (Pressure)
// val int S_WIND = 9 // Wind sensor
// val int S_RAIN = 10 // Rain sensor
// val int S_UV = 11 // UV sensor
// val int S_WEIGHT = 12 // Weight sensor for scales etc.
// val int S_POWER = 13 // Power measuring device, like power meters
// val int S_HEATER = 14 // Heater device
// val int S_DISTANCE = 15 // Distance sensor
// val int S_LIGHT_LEVEL = 16 // Light sensor
// val int S_ARDUINO_NODE = 17 // Arduino node device
// val int S_ARDUINO_REPEATER_NODE = 18 // Arduino repeating node device
// val int S_LOCK = 19 // Lock device
// val int S_IR = 20 // Ir sender/receiver device
// val int S_WATER = 21 // Water meter
// val int S_AIR_QUALITY = 22 // Air quality sensor e.g. MQ-2
// val int S_CUSTOM = 23 // Use this for custom sensors where no other fits.
// val int S_DUST = 24 // Dust level sensor
// val int S_SCENE_CONTROLLER = 25 // Scene controller device
// val int S_RGB_LIGHT = 26 // RGB light
// val int S_RGBW_LIGHT = 27 // RGBW light (with separate white component)
// val int S_COLOR_SENSOR = 28 // Color sensor
// val int S_HVAC = 29 // Thermostat/HVAC device
// val int S_MULTIMETER = 30 // Multimeter device
// val int S_SPRINKLER = 31 // Sprinkler device
// val int S_WATER_LEAK = 32 // Water leak sensor
// val int S_SOUND = 33 // Sound sensor
// val int S_VIBRATION = 34 // Vibration sensor
// val int S_MOISTURE = 35 // Moisture sensor
// SubTypes for MessageType M_SET //
val int V_TEMP = 0 // Temperature
val int V_HUM = 1 // Humidity
val int V_STATUS = 2 // Binary status. 0=off 1=on
val int V_LIGHT = 2 // Deprecated. Alias for V_STATUS. Light status. 0=off 1=on
val int V_PERCENTAGE = 3 // Percentage value. 0-100 (%)
val int V_DIMMER = 3 // Deprecated. Alias for V_PERCENTAGE. Dimmer value. 0-100 (%)
val int V_PRESSURE = 4 // Atmospheric Pressure
val int V_FORECAST = 5 // Whether forecast. One of "stable", "sunny", "cloudy", "unstable", "thunderstorm" or "unknown"
val int V_RAIN = 6 // Amount of rain
val int V_RAINRATE = 7 // Rate of rain
val int V_WIND = 8 // Windspeed
val int V_GUST = 9 // Gust
val int V_DIRECTION = 10 // Wind direction
val int V_UV = 11 // UV light level
val int V_WEIGHT = 12 // Weight (for scales etc)
val int V_DISTANCE = 13 // Distance
val int V_IMPEDANCE = 14 // Impedance value
val int V_ARMED = 15 // Armed status of a security sensor. 1=Armed, 0=Bypassed
val int V_TRIPPED = 16 // Tripped status of a security sensor. 1=Tripped, 0=Untripped
val int V_WATT = 17 // Watt value for power meters
val int V_KWH = 18 // Accumulated number of KWH for a power meter
val int V_SCENE_ON = 19 // Turn on a scene
val int V_SCENE_OFF = 20 // Turn of a scene
val int V_HVAC_FLOW_STATE = 21 // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver"
val int V_HVAC_SPEED = 22 // HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto")
val int V_LIGHT_LEVEL = 23 // Uncalibrated light level. 0-100%. Use V_LEVEL for light level in lux.
val int V_VAR1 = 24 // Custom value
val int V_VAR2 = 25 // Custom value
val int V_VAR3 = 26 // Custom value
val int V_VAR4 = 27 // Custom value
val int V_VAR5 = 28 // Custom value
val int V_UP = 29 // Window covering. Up.
val int V_DOWN = 30 // Window covering. Down.
val int V_STOP = 31 // Window covering. Stop.
val int V_IR_SEND = 32 // Send out an IR-command
val int V_IR_RECEIVE = 33 // This message contains a received IR-command
val int V_FLOW = 34 // Flow of water (in meter)
val int V_VOLUME = 35 // Water volume
val int V_LOCK_STATUS = 36 // Set or get lock status. 1=Locked, 0=Unlocked
val int V_LEVEL = 37 // Used for sending level-value
val int V_VOLTAGE = 38 // Voltage level
val int V_CURRENT = 39 // Current level
val int V_RGB = 40 // RGB value transmitted as ASCII hex string (I.e "ff0000" for red)
val int V_RGBW = 41 // RGBW value transmitted as ASCII hex string (I.e "ff0000ff" for red + full white)
val int V_ID = 42 // Optional unique sensor id (e.g. OneWire DS1820b ids)
val int V_UNIT_PREFIX = 43 // Allows sensors to send in a string representing the unit prefix to be displayed in GUI. This is not parsed by controller! E.g. cm, m, km, inch.
val int V_HVAC_SETPOINT_COOL = 44 // HVAC cold setpoint
val int V_HVAC_SETPOINT_HEAT = 45 // HVAC/Heater setpoint
val int V_HVAC_FLOW_MODE = 46 // Flow mode for HVAC ("Auto", "ContinuousOn", "PeriodicOn")
// SubTypes for MessageType M_INTERNAL //
val int I_BATTERY_LEVEL = 0 // Use this to report the battery level (in percent 0-100).
val int I_TIME = 1 // Sensors can request the current time from the Controller using this message. The time will be reported as the seconds since 1970
val int I_VERSION = 2 // Used to request gateway version from controller.
val int I_ID_REQUEST = 3 // Use this to request a unique node id from the controller.
val int I_ID_RESPONSE = 4 // Id response back to sensor. Payload contains sensor id.
val int I_INCLUSION_MODE = 5 // Start/stop inclusion mode of the Controller (1=start, 0=stop).
val int I_CONFIG = 6 // Config request from node. Reply with (M)etric or (I)mperal back to sensor.
val int I_FIND_PARENT = 7 // When a sensor starts up, it broadcast a search request to all neighbor nodes. They reply with a I_FIND_PARENT_RESPONSE.
val int I_FIND_PARENT_RESPONSE = 8 // Reply message type to I_FIND_PARENT request.
val int I_LOG_MESSAGE = 9 // Sent by the gateway to the Controller to trace-log a message
val int I_CHILDREN = 10 // A message that can be used to transfer child sensors (from EEPROM routing table) of a repeating node.
val int I_SKETCH_NAME = 11 // Optional sketch name that can be used to identify sensor in the Controller GUI
val int I_SKETCH_VERSION = 12 // Optional sketch version that can be reported to keep track of the version of sensor in the Controller GUI.
val int I_REBOOT = 13 // Used by OTA firmware updates. Request for node to reboot.
val int I_GATEWAY_READY = 14 // Send by gateway to controller when startup is complete.
val int I_REQUEST_SIGNING = 15 // Used between sensors when initialting signing.
val int I_GET_NONCE = 16 // Used between sensors when requesting nonce.
val int I_GET_NONCE_RESPONSE = 17 // Used between sensors for nonce response.
// MySensors 1.5 Configuration
///////////////////////////////
// Use the HashMap "sensorToItemsMap" to create a relation between the nodeID
// within MySensors and the item name in OpenHAB.
//
// Please note that you must map in both directions, so we can resolve both.
//
// EXAMPLE:
// "1;1;" -> "light_leroy_led",
// "light_leroy_led" -> "1;1;"
//
// Mappings
var HashMap<String, String> sensorToItemsMap = newLinkedHashMap(
"1;1;" -> "light_leroy_led",
"light_leroy_led" -> "1;1;",
"1;2;" -> "aacc_mode",
"aacc_mode" -> "1;2;",
"1;10;" -> "leroy_motion_tripped",
"leroy_motion_tripped" -> "1;10;",
"1;11;" -> "leroy_motion_armed",
"leroy_motion_armed" -> "1;11;",
"tv_ir" -> "105;1;"
)
////////////////////////////////////////////////////////////////////////////////////////////////////
val org.eclipse.xtext.xbase.lib.Functions$Function4 mysensors = [
String IDs,
int subType,
String data,
org.openhab.core.library.items.StringItem gw
|
if(!(data instanceof String)) println("\nERROR: data must be String but has " + data.getClass() + "\n")
var String new_data
if(data == "ON"){
new_data = new String("1")
}
else if (data == "OFF"){
new_data = new String("0")
}
else
{
new_data = new String(data)
}
var String output = IDs + "1;0;" + subType + ";" + new_data + "\n"
gw.sendCommand(output)
]
// Notes for this rule
// This is all you need to have MySensors set your items.
// It's better to hardcode the nodeID on your MySensors sensors,
// because openHAB will not assign them nodeIDs.
rule "Decode incoming MySensors data"
when
Item senso_irf24 changed
then
var String lineBuffer = senso_irf24.state.toString.split("\n")
for (String line : lineBuffer) {
var String[] message = line.split(";")
var Integer nodeId = new Integer(message.get(0))
var Integer childId = new Integer(message.get(1))
var Integer msgType = new Integer(message.get(2))
var Integer ack = new Integer(message.get(3))
var Integer subType = new Integer(message.get(4))
var String msg = message.get(5)
var String openhab_item = sensorToItemsMap.get( nodeId + ";" + childId + ";" )
if (nodeId != 0){ // internal messages have nodeId 0, but are not used for now
if (openhab_item == null){
println("No item matches nodeId=" + nodeId + ", childId=" + childId + ". Data received: " + msg)
}
else { // openhab_item != null
print("openhab_item=" + openhab_item + "\t")
print("msgType=" + msgType + " ")
var String newState = msg
if (msgType == M_SET){ // Set Command from or to node
println("(SET)\t subType=" + subType + " ")
if (subType == V_STATUS ){ if ( new Integer(msg) == 1 ) newState = "ON" else newState = "OFF" }
if (subType == V_ARMED ){ if ( new Integer(msg) == 1 ) newState = "ON" else newState = "OFF" }
else if (subType == V_TRIPPED){ if ( new Integer(msg) == 1 ) newState = "tripped" else newState = "untripped" }
else println("No special handler for subType=" + subType + " found. Simply using data as String.")
postUpdate(openhab_item, newState)
}
if(msgType == M_INTERNAL){ // Internal Command
print("(INTERNAL)\t")
if(subType == I_SKETCH_NAME){
println("Sketch name: " + msg )
}
if(subType == I_SKETCH_VERSION){
println("Sketch version: " + msg )
}
}
} // openhab_item != null
}
}
}
end
// RULES ////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Notes: If you want to send something to a MySensors sensor/actuator,
// you can use the lamda "mysensors" which we assigned above.
//
// EXAMPLE:
rule "Poweron LG TV"
when Item leroy_tv_ison received command ON
then
mysensors.apply(sensorToItemsMap.get("tv_ir"), V_IR_SEND, "1,20DF23DC,32", senso_irf24)
end
// "tv_ir" is mapped to the nodeID 105, sensorID 1 (see sensorToItemsMap above)
// "V_IR_SEND" is the type of data we send.
// "1,20DF23DC,32" is the NEC command "PowerOn LG TV" with a lenght of 32 bit (from Arduino IRLib.h)
// (Find my other LG TV discrete ir hex codes here: https://gist.github.com/gersilex/1df3b881e219d04f0456)
// In MySensor terms, this is simply, the data we send. Could be any String.
// "senso_irf24" is the String Item with the serial binding of the MySensors Serial Gateway.
// Another EXAMPLE:
rule "Luminium set LightMode"
when Item aacc_mode received command
then
if(receivedCommand == "sleep"){
timer = createTimer(now.plusSeconds(10)) [|
postUpdate(light_leroy_led, OFF)
]
}
else
{
switch(receivedCommand){
case ON: sendCommand(light_leroy_led, ON)
case OFF: sendCommand(light_leroy_led, OFF)
default: mysensors.apply(sensorToItemsMap.get("aacc_mode"), V_VAR1, receivedCommand.toString(), senso_irf24)
}
}
end
// If "aacc_mode" is a number, this will be forwarded as type "V_VAR1" (Custom) to the MySensors Light Actuator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment