Mysensors on OH2: hashmap.get error appears at startup, but not always

I have tried searching the forum for my particular problem, but haven’t found anything which can help.
My openHAB2 on Raspberry Pi 3 is connected to DIY sensors and actuators (relay, reed switch, and PIR sensor) using mysensors serial gateway. I started having this problem after migration to openHAB2 (offline apt-get installation) from openHAB1.8

Here is my problem : During openHAB2 startup, after loading models, the following error occured and opanHAB2 can’t seem to communicate with mysensors node.
2016-07-22 05:42:43.114 [ERROR] [.script.engine.ScriptExecutionThread] - Error during the execution of rule ‘Arduino sends to Openhab’: cannot invoke method public java.lang.Object java.util.HashMap.get(java.lang.Object) on null

However, this error not appearing 100% of the time, but only roughly 95% of the system startup experienced this error. Dummy edit to rules file fixed it, and openHAB2 started working as expected again. Same items, sitemap, and rules were not having this issue on openHAB1.8

My guess fix to this problem:

  • Rules file were not loaded last. When i check the openhab log, during startup models were loaded in the following order : sitemap, rules, items. I have tried searching the forum on how to change the order on openHAB2 and checked around my openHAB2 installation folder, but can’t seem to find it.
  • For whatever reason this error appears, openHAB2 should work fine if i configure my rules to be refreshed when such error occured. However, i have little to no idea how this can be achieved in openhab.

Can anyone help me on how to fix this problem?

I have two separate rules files, first one consists of automation i run around the house, the other handles openHAB2 communication with mysensors node. Here is my rule for the later one:

import org.openhab.core.persistence.*
import java.util.*
import org.eclipse.xtext.xbase.lib.*
import org.openhab.core.items.*
import org.joda.time.*
import org.openhab.core.library.types.*
import org.openhab.model.script.actions.*
import java.util.HashMap
import java.util.LinkedHashMap

//Variable for wireless receiver
var String ArduinoUpdate = ""
var String sketchName = ""
var int V_TEMP = 0
var int V_HUM = 1
var int V_LIGHT = 2
var int V_DIMMER = 3
var int V_PRESSURE = 4
var int V_FORECAST = 5
var int V_RAIN = 6
var int V_RAINRATE = 7
var int V_WIND = 8
var int V_GUST = 9
var int V_DIRECTION = 10
var int V_UV = 11
var int V_WEIGHT = 12
var int V_DISTANCE = 13
var int V_IMPEDANCE = 14
var int V_ARMED = 15
var int V_TRIPPED = 16
var int V_WATT = 17
var int V_KWH = 18
var int V_SCENE_ON = 19
var int V_SCENE_OFF = 20
var int V_HEATER = 21
var int V_HEATER_SW = 22
var int V_LIGHT_LEVEL = 23
var int V_VAR1 = 24
var int V_VAR2 = 25
var int V_VAR3 = 26
var int V_VAR4 = 27
var int V_VAR5 = 28
var int V_UP = 29
var int V_DOWN = 30
var int V_STOP = 31
var int V_IR_SEND = 32
var int V_IR_RECEIVE = 33
var int V_FLOW = 34
var int V_VOLUME = 35
var int V_LOCK_STATUS = 36
var int V_DUST_LEVEL = 37
var int V_VOLTAGE = 38
var int V_CURRENT = 39
var int msgPresentation = 0
var int msgSet = 1
var int msgReq = 2
var int msgInternal = 3
var int msgStream = 4
var int alarmArmor = 1
// Internal Commands
var int I_BATTERY_LEVEL = 0
var int I_TIME = 1
var int I_VERSION = 2
var int I_ID_REQUEST = 3
var int I_ID_RESPONSE = 4
var int I_INCLUSION_MODE = 5
var int I_CONFIG = 6
var int I_FIND_PARENT = 7
var int I_FIND_PARENT_RESPONSE = 8
var int I_LOG_MESSAGE = 9
var int I_CHILDREN = 10
var int I_SKETCH_NAME = 11
var int I_SKETCH_VERSION = 12
var int I_REBOOT = 13
var int I_GATEWAY_READY = 14

// Mappings of each house items to its "node_id;child_id;" format
// This mappings is necessary to translate difference in items' name format for openhab and mysensor nodes
var HashMap<String, String> sensorToItemsMap = newLinkedHashMap(
    "102;1;"            		-> "GF_Bedroom_MainRoom_1",
    "GF_Bedroom_MainRoom_1"     -> "102;1;",
    "102;2;"            		-> "GF_Bedroom_MainRoom_2",
    "GF_Bedroom_MainRoom_2"  	-> "102;2;",
    "102;3;"            		-> "GF_Bedroom_Main_WC",
    "GF_Bedroom_Main_WC"        -> "102;3;",
    "102;4;"            		-> "GF_Dining_Corridor_1",
    "GF_Dining_Corridor_1"  	-> "102;4;",
    "102;6;"            		-> "GF_Bedroom_WC_Mot",
    "GF_Bedroom_WC_Mot"  		-> "102;6;",
    "103;1;"            		-> "GF_Living_1",
    "GF_Living_1"   		    -> "103;1;",
    "103;2;"            		-> "GF_Living_2",
    "GF_Living_2"   		    -> "103;2;",
    "103;3;"            		-> "GF_Living_3",
    "GF_Living_3"   		    -> "103;3;",
    "103;5;"            		-> "GF_Living_4",
    "GF_Living_4"   		    -> "103;5;",
    "103;4;"            		-> "GF_Outdoor_Light_Front",
    "GF_Outdoor_Light_Front" 	-> "103;4;",
    "103;6;"            		-> "GF_Dining_Cor_Mot",
    "GF_Dining_Cor_Mot"   		-> "103;6;",
    "103;7;"            		-> "GF_Living_Sofa_Mot",
    "GF_Living_Sofa_Mot"   		-> "103;7;",
    "104;3;"            		-> "GF_Dining_2",
    "GF_Dining_2"   		    -> "104;3;",
    "104;1;"            		-> "GF_Kitchen_1",
    "GF_Kitchen_1"   		    -> "104;1;",
    "104;2;"            		-> "GF_Outdoor_Light_Back",
    "GF_Outdoor_Light_Back"	    -> "104;2;",
    "104;5;"            		-> "GF_Dining_2_Mot",
    "GF_Dining_2_Mot"   		-> "104;5;",
    "104;4;"            		-> "GF_Kitchen_1_Mot",
    "GF_Kitchen_1_Mot"   		-> "104;4;",
    "105;4;"            		-> "GF_Dining_1_Mot",
    "GF_Dining_1_Mot"   		-> "105;4;",
    "201;3;"					-> "Indihome_Power",
    "Indihome_Power"			-> "201;3;"
)
// This variable is for header option for transciving message using mysensor protocol
var String MysensorHeaderOpt = "1;0;2;"

/* Receive Mysensors sensor info wirelessly
 * Do not need any modification for each house architecture, but may need modification for different type of sensors
 * This rule is not typical rule, but more like a binding for mysensor sensors for use in openhab
 */
//receiving msg from mysensors gateway
rule "Arduino sends to Openhab"
when
    Item Arduino received update
then
    var String[] lineBuffer =  Arduino.state.toString.split("\n")
    for (String line : lineBuffer) {
        var String[] message = line.split(";")
        //logInfo("org.openhab","Received message from gateway" + message)
        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)
        if(msgType == 1 ){
            if (subType == V_TEMP){
                postUpdate(sensorToItemsMap.get( nodeId + ";" + childId + ";"), msg)
                println ("Temp item: " + sensorToItemsMap.get( nodeId + ";" + childId + ";") + " temp: " + msg )
            }
            if (subType == V_HUM){
                postUpdate(sensorToItemsMap.get( nodeId + ";" + childId + ";"), msg)
                println ("Hum item: " + sensorToItemsMap.get( nodeId + ";" + childId + ";") + " hum: " + msg )
            }
            if (subType == V_LIGHT_LEVEL){
                postUpdate(sensorToItemsMap.get( nodeId + ";" + childId + ";"), msg)
                println ("Light item: " + sensorToItemsMap.get( nodeId + ";" + childId + ";") + " light: " + msg )
            }
            if (subType == V_VOLTAGE){
                postUpdate(sensorToItemsMap.get( nodeId + ";" + childId + ";"), msg)
                println ("Voltage item: " + sensorToItemsMap.get( nodeId + ";" + childId + ";") + " voltage: " + msg )
            }
            if (subType == V_LOCK_STATUS){
                var String lockstatus="OPEN" 
                if (msg=="1"){
                    lockstatus="CLOSED"
                } 
                postUpdate(sensorToItemsMap.get( nodeId + ";" + childId + ";"), lockstatus)
                println ("Door/Window item: " + sensorToItemsMap.get( nodeId + ";" + childId + ";") + " Status: " + lockstatus )
            }
            if (subType == V_TRIPPED){
                var String tripped="CLOSED"
                if (msg=="1"){
                    tripped="OPEN"
                }
                postUpdate(sensorToItemsMap.get( nodeId + ";" + childId + ";"), tripped)
                println ("Button/Contact item: " + sensorToItemsMap.get( nodeId + ";" + childId + ";") + " Status: " + tripped )
            }
            if (subType == V_LIGHT){
                var String light="OFF"
                if (msg=="1"){
                    light="ON"
                }
                postUpdate(sensorToItemsMap.get( nodeId + ";" + childId + ";"), light)
                println ("Light item: " + sensorToItemsMap.get( nodeId + ";" + childId + ";") + " Light: " + light )
            }
        }
        // Internal Command
        if(msgType == 3){
            if(subType == I_SKETCH_NAME){
                    println("Sketch name: " + msg )
                    sketchName=msg
            }
            if(subType == I_SKETCH_VERSION){
                    println("Sketch version: " + msg )
                    postUpdate(sensorToItemsMap.get( nodeId + ";" + childId + ";"), sketchName+" " +msg )
                    sketchName=""
            }
        }
    }   
end

/* Send info wirelessly to each mysensor actuator nodes
 * Need modifications for each house items. Just copy paste one block of rule, and change item name correspondingly
 * This rule is not typical rule, but more like a binding for mysensor actuators for use in openhab
 * This rule block only design to work with relays. Other type of actuators may need modification
 */
rule "Send Arduino Command to Actuator"
when
    Item GF_Outdoor_Light_Front changed
then
    var String state="0"
    if (GF_Outdoor_Light_Front.state == ON){
    	state = "1"
    }
    sendCommand(Arduino, sensorToItemsMap.get( "GF_Outdoor_Light_Front" ) + MysensorHeaderOpt + state + "\n")
end
rule "Send Arduino Command to Actuator"
when
    Item GF_Living_1 changed
then
    var String state="0"
    if (GF_Living_1.state == ON){
    	state = "1"
    }
    sendCommand(Arduino, sensorToItemsMap.get( "GF_Living_1" ) + MysensorHeaderOpt + state + "\n")
end
rule "Send Arduino Command to Actuator"
when
    Item GF_Living_2 changed
then
    var String state="0"
    if (GF_Living_2.state == ON){
    	state = "1"
    }
    sendCommand(Arduino, sensorToItemsMap.get( "GF_Living_2" ) + MysensorHeaderOpt + state + "\n")
end
rule "Send Arduino Command to Actuator"
when
    Item GF_Living_3 changed
then
    var String state="0"
    if (GF_Living_3.state == ON){
    	state = "1"
    }
    sendCommand(Arduino, sensorToItemsMap.get( "GF_Living_3" ) + MysensorHeaderOpt + state + "\n")
end
rule "Send Arduino Command to Actuator"
when
    Item GF_Living_4 changed
then
    var String state="0"
    if (GF_Living_4.state == ON){
    	state = "1"
    }
    sendCommand(Arduino, sensorToItemsMap.get( "GF_Living_4" ) + MysensorHeaderOpt + state + "\n")
end
rule "Send Arduino Command to Actuator"
when
    Item GF_Bedroom_MainRoom_1 changed
then
    var String state="0"
    if (GF_Bedroom_MainRoom_1.state == ON){
    	state = "1"
    }
    sendCommand(Arduino, sensorToItemsMap.get( "GF_Bedroom_MainRoom_1" ) + MysensorHeaderOpt + state + "\n")
end
rule "Send Arduino Command to Actuator"
when
    Item GF_Bedroom_MainRoom_2 changed
then
    var String state="0"
    if (GF_Bedroom_MainRoom_2.state == ON){
    	state = "1"
    }
    sendCommand(Arduino, sensorToItemsMap.get( "GF_Bedroom_MainRoom_2" ) + MysensorHeaderOpt + state + "\n")
end
rule "Send Arduino Command to Actuator"
when
    Item GF_Bedroom_Main_WC changed
then
    var String state="0"
    if (GF_Bedroom_Main_WC.state == ON){
    	state = "1"
    }
    sendCommand(Arduino, sensorToItemsMap.get( "GF_Bedroom_Main_WC" ) + MysensorHeaderOpt + state + "\n")
end
rule "Send Arduino Command to Actuator"
when
    Item GF_Dining_Corridor_1 changed
then
    var String state="0"
    if (GF_Dining_Corridor_1.state == ON){
    	state = "1"
    }
    sendCommand(Arduino, sensorToItemsMap.get( "GF_Dining_Corridor_1" ) + MysensorHeaderOpt + state + "\n")
end
rule "Send Arduino Command to Actuator"
when
    Item GF_Dining_2 changed
then
    var String state="0"
    if (GF_Dining_2.state == ON){
    	state = "1"
    }
    sendCommand(Arduino, sensorToItemsMap.get( "GF_Dining_2" ) + MysensorHeaderOpt + state + "\n")
end
rule "Send Arduino Command to Actuator"
when
    Item GF_Kitchen_1 changed
then
    var String state="0"
    if (GF_Kitchen_1.state == ON){
    	state = "1"
    }
    sendCommand(Arduino, sensorToItemsMap.get( "GF_Kitchen_1" ) + MysensorHeaderOpt + state + "\n")
end
rule "Send Arduino Command to Actuator"
when
    Item GF_Outdoor_Light_Back changed
then
    var String state="0"
    if (GF_Outdoor_Light_Back.state == ON){
    	state = "1"
    }
    sendCommand(Arduino, sensorToItemsMap.get( "GF_Outdoor_Light_Back" ) + MysensorHeaderOpt + state + "\n")
end
rule "Send Arduino Command to Actuator"
when
    Item Indihome_Power received command
then
    //var String state="1"
    sendCommand(Arduino, sensorToItemsMap.get( "Indihome_Power" ) + MysensorHeaderOpt + "1" + "\n")
end

In OH 1 there are parameters in openhab.cfg that define the polling period in seconds for how often OH checks for changes to the various file types. These parameters started with “folder” as in “folder:rules”. I’m not sure if that helps you find the equivalent in OH 2, assuming they are still there.

You can create a System started triggered with:

Thread::sleep(20000)
executeCommandLine("touch /etc/openhab/configurations/rules/*.rules")

or where ever the OH 2 rules files are kept (NOTE: above only works on Linux or OSX, Windows works a different way).

The specific error though doesn’t feel like it is related to Items not being there so much as it feels like your Arduino is receiving an update before the rules file is fully loaded and processed. In short, “Arduino sends to Openhab” (btw correct spelling is openHAB) is triggered before sensorToItemsMap is done being initialized. If that is indeed the problem, changing the order or touching the file will not solve the problem.

Instead you need to create a lockout for a brief period while OH is starting and ignore any Arduino updates until the hashmap is populated.

This can be achieved by simple adding a check at the top of the Arduino rule:

if(sensorToItems == null) {
    logWarn("Arduino", "Received Arduino update before we were ready, ignoring")
    return false
}
1 Like

Thank you for your informative and very fast response. I tried approaches that you mentioned separately with the following result :

  • Create a lockout for a brief period

Results: I tried this and things improved. Now it is only 1 out of 10 startup which resulted in hashmap error (the hashmap error was replaced with the “Received Arduino update before we were ready, ignoring”). Will try again within next week to check whether this is only random event or not.

  • Auto refresh rules using System started trigger

Results : After refreshing rules model, the hashmap error that i mentioned was gone. However, openHAB2 went into refreshing loop. It seems like the system started trigger is based on the rules being finished loading.
As temporary solution, I created a switch item, which will execute the touch command line when pressed (didn’t know such command exists in Linux, thank you). A lot more convenient now, being able to refresh the rule from the user UI. Still hoping for a fully automatic rule refresh solution though.

DOH! Yes, that would be a problem. To make this work you would need to have the System started rule in a different rules file from everything else and change the executeCommandLine to only touch the other rules files and never the System started.

That confirms my suspicion. The problem is that your Arduinos are constantly sending updates to openHAB and occasionally the timing will be such that the Arduino sends an update while the rule is being loaded. This means that your Items are actually being loaded before the rules; otherwise there wouldn’t be an event to trigger the rule before the rule was ready.

Given this is the case, the reload of the files will not really solve this problem. In fact, forcing your Items to load AFTER the rules would probably be a more reliable solution to this particular problem but it likely would cause all sorts of other problems.

One thing you can try is to move the definition of the HashMap inside the rule. This lets you sidestep the problem of the HashMap not being initialized when the rule triggers since the rule will create the HashMap itself. Of course, if the HashMap is used somewhere else then this is a less than satisfactory solution. Also, if the Items are still being loaded when the rule does trigger then you will have other problems.

1 Like

I didn’t realize such an obvious solution. Thank you for mentioning it. I need to put around 60 seconds of sleep time, otherwise ‘rules cannot be parsed correctly’ error appeared. Although startup time become significantly longer, this still works for me.

Your argument makes sense. However, out of curiosity, I tried deleting that line of code from my rules, and the hashmap error appearance is not as bad as before. Then i tried rebooting many times (100 times; to get more reliable statement than what i stated in previous posts) and comparing openhab startup with and without that line of code. Here are results of that experiment. With that line of code, hashmap error appeared 27.5% of the times. While without that line of code, hashmap error appeared 25% of the times. I concluded that openhab startup will be the same with or without that line of code.

I am convinced by your argument that the reason this error appears is as you stated. I believe it is just the code that didn’t successfully create a lockout for Arduino updates while openhab is loading.

This indeed might solve the problem, however, as you said, lots of other rules use the HasMap, so putting HashMap into each rule beats the purpose of using HashMap in the first place. The auto-refresh solution still works best for me.
Thank you for your time in helping me with my problem! :smile: