Please advise on moving rules from older version to OH 3

Hi,

I have been running OH for several years. I started with version 1, then did an upgrade to v2, without any change in config (at least, I don’t remember changing anything significant, it was years ago). Now I’m in the process of moving to v3. I decided to do clean install (see my config below) and then recreate objects (items, rules, etc) manually. My question is - should rules written for v1 run on v3? Can I just copy the rule body into “Then” part of the rule being created and expect it to execute? Do I understand it right that DSL is basically the same language used in previous versions for writing rules?

If yes, then I’ll come back with more specific example not being executed.

Veiksmi,
Jānis

  • Platform information:
    • Hardware: Raspberry Pi 2 /RAM 1GB/storage 16GB
    • OS: OpenHABian
    • Java Runtime Environment:
      openjdk version “11.0.18” 2023-01-17
      OpenJDK Runtime Environment (build 11.0.18+10-post-Raspbian-1deb11u1)
      OpenJDK Server VM (build 11.0.18+10-post-Raspbian-1deb11u1, mixed mode)
    • openHAB version: 3.4.2

Yes, mostly. An update to major versions almost always comes with some breaking changes. There were a few between 2 and 3. The parameters of executeCommandLine is a common one that comes to mind. But as with any such move, you’ll really just have to try it and see.

With OH3 there is the new Remote openHab binding which lets one (at least OH3) instance read all the items of a second (at least OH2) instance. Many people used this as a way to do the migration piecemeal by setting up parallel items in the two and moving/troubleshooting rules one at a time.

The bigger issue may be your bindings. OH2 still allowed the older V1 bindings, but in OH3 those are completely incompatible. SO if you’ve kept any of those old binding versions you’ll now have to work with the new versions (if they exist) and reconfiguring your things.

Thanks for the reply!

Incompatibility of bindings was one of the reasons I decided to move manually. All 3 bindings I use (Serial, Modbus, DSCAlarm) are set up from scratch in the new environment and the Things made accordingly, working.

The rule in question is meant for updating an Item state when changes are received from Modbus. There is an Number Item which is connected to the Modbus poll Thing. That number is representing state of 16 physical devices (contacts) - if the binary position contains 0 the contact is off, on if 1. The rule is meant to extract state to another Item representing a single contact so I can use this Item normally in automation.

The rule body is the following:

if ( ( CG_AB_Modbus_Data_Value_as_Number.state as DecimalType ).toBigDecimal.toBigInteger.testBit( 10 ) != ( CG_AB_Modbus_Data_Value_as_Number_Previous.state as DecimalType ).toBigDecimal.toBigInteger.testBit( 10 ) )
		if ( ( CG_AB_Modbus_Data_Value_as_Number.state as DecimalType ).toBigDecimal.toBigInteger.testBit( 10 ) )
			postUpdate( Corridor_Light, ON )
			else postUpdate( Corridor_Light, OFF )
    
    postUpdate( CG_AB_Modbus_Data_Value_as_Number_Previous, CG_AB_Modbus_Data_Value_as_Number.state ) 

Rule triggers, but never ends executing. I have not learned yet how can I see the right log in order to debug / see what actually happens there.

Ok, I got it, logging is the same as previously, events.log and openhab.log. I can see that OH does not like casting Item.state as DecimalType which worked in previous version. Means language has changed… Some learning ahead :slight_smile:

It’s been a while since I’ve used DSL, but try as Number instead.

Thanks, as Number works.

.testBit method does not for type int thou…

Sorry, I didn’t look at your whole code.

Assuming your item is a number type, which appears to be the case, then it is already a BigDecimal (if I recall rightly) and you don’t have to cast it at all. You should then just be able to jump immediately to converting it to BigInteger.

CG_AB_Modbus_Data_Value_as_Number.state.toBigInteger.testBit( 10 )

As a side note, DSL is not going anywhere, as far as everyone knows it will remain fully supported and no one is discouraged from using it. However, it is awkward (especially for people like me who know little to no java) and at this point is it the least feature-rich and capable of the scripting options. With the new 4.0 coming out soon it will no longer be the default and will have to be installed as with any of the other scripting languages. Many people (myself included) took the upgrade from 2 → 3 as an excuse to also transition to one of the newly available, more modern scripting options. I’m not saying you have to convert, just pointing out that there won’t ever really be a better time if it’s something you’ve been on the fence about.

Still no luck.

The item CG_AB_Modbus_Data_Value_as_Number is of type Number indeed. But your suggestion results in an error: The method or field toBigInteger is undefined for the type State.

Maybe this is an issue of importing some library not available by default?

PS I’m not familiar with Java. I’ll give a thought to moving away from DSL.

Take a good look at the UI rules, particularly using Blockly.

I’m still using DSL, because transitioning my rules keeps getting pushed down my priority list. As Justin said, there’s no rush to move away from DSL, but there’s benefit to doing so in the long term.

I read an intro to UI rules. I’m afraid there will be no means for analysing bit values I receive via modbus. But I’m not sure. Will investigate.

The rule you posted is really just an if/else statement, and it seems like the tricky part is getting the values into a comparable format. I don’t know ModBus, but I’d be surprised if that’s not possible in Blockly. If that does end up being the case, you can use a script action to keep your DSL (or use another language).

I’m guessing that many of my rules will break down into very simple if statements that don’t even require Blockly (particularly since rules can be triggered by other rules). But I’ll also have some edge cases that have to be handled a bit differently.

DSL has a bunch of “under the hood” modifications that are supposed to make coding a little nicer. I’ve forgotten most of the few that I knew, but I thought it could automatically cast the state to it’s default type…apparently not. So you do still need the as DecimalType which means the only potential issue with your initial code could be that DSL now requires the methods to be explicitly written in function syntax. So, for example, instead of toBigDecimal you need toBigDecimal(), etc.:

( CG_AB_Modbus_Data_Value_as_Number.state as DecimalType ).toBigDecimal().toBigInteger().testBit( 10 )

For comparison, JSscripting has simple bitwise operators, so the equivalent code would be:

(Number.parseInt(items.getItem('CG_AB_Modbus_Data_Value_as_Number').state) & 1024

or if you jump to OH4 and the newest JSscripting you can reduce that further to:

(Number.parseInt(items.CG_AB_Modbus_Data_Value_as_Number.state) & 1024

Blockly won’t have the bitwise operators directly, I believe, but it does have a block where you can insert your own arbitrary code, so you could work up the bitwise calculation with regular blocks and then throw in that top javascript line with the code block.

2 Likes

Available in openHAB 4.0.0 Milestone 1: [Blockly] Add bitwise math operators by stefan-hoehn · Pull Request #1722 · openhab/openhab-webui · GitHub

3 Likes

Adding brackets solves it! Big thanks!

As there are a lot of bitwise analysis in my case because of the modbus, it seems worth waiting for OH 4 where bit operations seem to be expected in Blockly.

Just to check, you mean “wait until OH4 to change your rules”, not “go back to OH2 and then wait for OH4”? The reason I ask is the log4j2 exploit from two years ago. It was patched in OH3, but not in OH2 (for technical reasons). The sooner we get people off of OH2, the better.

I meant the first when I wrote the post.

But today I think I’ll stay with OH 2. I tried to move another rule to OH 3 and failed again, this time there is even no error explanation, simply “script failed” in the log. I have too little programming knowledge in this language and patience / too low priority for this in order to debug every row of my rules file. It’s close to 1500 rows, the cost of moving seem simply too high.

Even thou I hardly believe anyone will be able to see where the problem is, I post the failing rule here. Just for history in worst case :joy:

rule "Split-decode-process Arduino Message"
	when
    	Item Arduino changed
	then
		var String[] linebuffer =  Arduino.state.toString.split("\n") // Split whole message string into messages separated with NEWLINE and put into array
		for (String element : linebuffer) {
			var String[] buffer = element.split(";") // Split message according to MySensors serial protocol:
										// node-id;child-sensor-id;message-type;ack;sub-type;payload\n
										// http://www.mysensors.org/download/serial_api_15
			var int NodeID = new Integer(buffer.get(0))
			var int SensorID = new Integer(buffer.get(1))
			var int MessageType = new Integer(buffer.get(2))
			var int MessageSubType = new Integer(buffer.get(4))
//			var int Ack = new Integer(buffer.get(3)) // Not used most probably
			var String Message = buffer.get(5)

			switch NodeID {
			case 0: { // Node ID = 0 is Gateway
				
//				if ( SensorID == 0 &&
//					MessageType == MessageTypeIsInternal &&
//					Ack == 0 &&
//					MessageSubType == I_LOG_MESSAGE ) { // Seem like normal MySensors gateway log message
//					
//					var String RW = Message.substring(0,4)
//					// postUpdate( ForDebug, "RW: "+RW )
//					switch RW {
//					case "read": {} // postUpdate( ForDebug, "Log message received from gateway of type READ: "+element)
//					case "send": {
//						// postUpdate( ForDebug, "Log message received from gateway of type SEND: "+element)
//						if ( Message.contains( "st=fail" )) {
////							postUpdate( ForDebug, "SEND FAIL log message received from gateway: "+element)
//							
//							// Get Node ID
//							var int ToNodeID = new Integer( Message.substring( Message.indexOf( "0-0-" ) + 4, Message.indexOf( "-", Message.indexOf( "0-0-" ) + 5 ) ) )
////							postUpdate( ForDebug, "SEND FAILed to Node ID: " + ToNodeID.toString() )
//							
//							// Get Sensor ID
//							var int ToSensorID = new Integer( Message.substring( Message.indexOf( "s=" ) + 2, Message.indexOf( ",", Message.indexOf( "s=" ) + 3 ) ) )
////							postUpdate( ForDebug, "SEND FAILed to Sensor ID: " + ToSensorID.toString() )
//							
//							// Get message type
//							var int ToMessageType = new Integer( Message.substring( Message.indexOf( "c=" ) + 2, Message.indexOf( ",", Message.indexOf( "c=" ) + 3 ) ) )
////							postUpdate( ForDebug, "SEND FAILed to Message Type: " + ToMessageType.toString() )
//							
//							// Get message sub-type
//							var int ToMessageSubType = new Integer( Message.substring( Message.indexOf( "t=" ) + 2, Message.indexOf( ",", Message.indexOf( "t=" ) + 3 ) ) )
////							postUpdate( ForDebug, "SEND FAILed to Message Sub Type: " + ToMessageSubType.toString() )
//							
//							// Get message
//							var int ToMessageLen = new Integer( Message.substring( Message.indexOf( "l=" ) + 2, Message.indexOf( ",", Message.indexOf( "l=" ) + 3 ) ) )
//							var String ToMessage = Message.substring( Message.indexOf( ":", Message.indexOf( "l=" ) ) + 1, Message.indexOf( ":", Message.indexOf( "l=" ) ) + ToMessageLen + 1 )
////							postUpdate( ForDebug, "SEND FAILed to Message: " + ToMessage + " " + Message.indexOf( ":", Message.indexOf( "l=" ) ).toString )
//							
//							if ( ToMessageType == ToMessageType && ToMessageSubType == V_PERCENTAGE ) {
//								sendCommand( Arduino, ToNodeID.toString()+";"+ToSensorID.toString()+";"+ToMessageType.toString()+";0;"+ToMessageSubType.toString()+";"+ToMessage+"\n")
//							}
//
//						}
//					}
//					default: postUpdate( ForDebug, "This sould have never happened! Unknown type log message from gateway: "+element )
//					}
//				} else postUpdate( ForDebug, "This sould have never happened! Unknown message from gateway: "+element )
			}
			case 1: { // Node ID = 1 is Outside sensor
				
				switch SensorID {
					case 255: { // System message?
						if ( MessageType == MessageTypeIsPresentation && MessageSubType == S_ARDUINO_NODE ) {	// If this is:
							// presentation message
							// and
							// Arduino node is presented
							postUpdate( ForDebug, "Arduino node has presented itself. Doing nothing for now. "+element)
						} if ( MessageType == MessageTypeIsInternal && MessageSubType == I_CONFIG ) {	// If this is:
							// an internal message
							// and
							// node is requesting config ((M)etric or (I)mperial)
							postUpdate( Arduino, "1;255;3;0;6;M" )
						} else {
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
						}
					}
					case 0: { // Sensor ID = 0 is DHT humidity sensor
						if ( MessageType == MessageTypeIsSet && MessageSubType == V_HUM ) {	// If this is:
							// sensor value set message
							// and
							// message is of V_HUM type
							postUpdate(OutsideHumidity, Message)
						} else {
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
						}
					}
					case 1: { // Sensor ID = 1 is DHT temperature sensor
						if ( MessageType == MessageTypeIsSet && MessageSubType == V_TEMP ) { // If this is:
							// sensor value set message
							// and
							// message is of V_TEMP type
							postUpdate(OutsideTempDHT, Message)
						} else {
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
						}
					}
					case 2: { // Sensor ID = 2 is BMP atmosphere pressure sensor
						if ( MessageType == MessageTypeIsSet && MessageSubType == V_PRESSURE ) { // If this is:
							// sensor value set message
							// and
							// message is of V_PRESSURE type
							postUpdate(Pressure, Message)
						} else if ( MessageType == MessageTypeIsSet && MessageSubType == V_FORECAST ) { // If this is:
							// sensor value set message
							// and
							// message is of V_FORECAST type
							postUpdate(WeatherForecast, Message)
						} else {
							postUpdate(ForDebug, "This sould have never happened! Unknown message: "+element)
						}
					}
					case 3: { // Sensor ID = 3 is BMP temperature sensor
						if ( MessageType == MessageTypeIsSet && MessageSubType == V_TEMP ) { // If this is:
							// sensor value set message
							// and
							// message is of V_TEMP type
							postUpdate(OutsideTempBMP, Message)
						} else {
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
						}
					}
					case 4: { // Sensor ID = 4 is soil moisture sensor
						if ( MessageType == MessageTypeIsSet && MessageSubType == V_RAIN ) { // If this is:
							// sensor value set message
							// and
							// message is of V_RAIN type, NOTE that wrong type is used, V_LEVEL and S_MOISTURE should be used
							postUpdate(SoilMoisture, Message)
						} else {
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
						}
					}
					case 5: { // Sensor ID = 3 is DS temperature sensor
						if ( MessageType == MessageTypeIsSet && MessageSubType == V_TEMP ) { // If this is:
							// sensor value set message
							// and
							// message is of V_TEMP type
							postUpdate(OutsideTempDS, Message)
						} else {
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
						}
					}
					case 255: { // Sensor ID = 255 is service ID
							postUpdate( ForDebug, "This is a service message: "+element )
					}
					default: postUpdate( ForDebug, "This sould have never happened! Node ID = 1, undefined Sensor ID encountered. Message: "+element )
				}
			}
			case 2: { // Node ID = 2 is Corridor (sensor)
				
				switch SensorID {
					case 0: { // Sensor ID = 0 is DHT humidity sensor
						if ( MessageType == MessageTypeIsSet && MessageSubType == V_HUM ) {	// If this is:
							// sensor value set message
							// and
							// message is of V_HUM type
							postUpdate(InsideHumDHT, Message)
						} else {
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
						}
					}
					case 1: { // Sensor ID = 1 is DHT temperature sensor
						if ( MessageType == MessageTypeIsSet && MessageSubType == V_TEMP ) { // If this is:
							// sensor value set message
							// and
							// message is of V_TEMP type
							postUpdate(InsideTempDHT, Message)
						} else {
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
						}
					}
					case 2: { // Sensor ID = 2 is TSL2561 light sensor
						if ( MessageType == MessageTypeIsSet && MessageSubType == V_LIGHT_LEVEL ) { // If this is:
							// sensor value set message
							// and
							// message is of V_LIGHT_LEVEL type, NOTE that wron type is used, V_LEVEL and S_LIGHT_LEVEL should be used
							postUpdate(IntsideLight, Message)
						} else {
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
						}
					}
					case 255: { // Sensor ID = 255 is service ID
							postUpdate( ForDebug, "This is a service message: "+element )
					}
					default: postUpdate( ForDebug, "This sould have never happened! Node ID = 2, undefined Sensor ID encountered. Message: "+element )
					
				}
			}
			case 3: { // Node ID = 3 is Living room fireplace
//				// const byte ButtonNr[9] = { 0, 1, 2, 5, 4, 8, 7, 6, 3 };
//				if ( SensorID >= 0 && SensorID <= 8 ) {
//						if ( MessageType == MessageTypeIsSet && MessageSubType == V_STATUS ) {	// If this is:
//							// sensor value set message
//							// and
//							// message is of V_STATUS type
//							if ( Message == "1" ) postUpdate( ForDebug, "Node ID = 3 button " + SensorID + " is ON" )
//							else if ( Message == "0" ) postUpdate( ForDebug, "Node ID = 3 button 0 is OFF" )
//							else postUpdate( ForDebug, "This is impossible! Node ID = 3 button message neither ON nor OFF, message: "+element)
//								
//						} else {
//							postUpdate( ForDebug, "This sould have never happened! Node ID = 3, undecode message type/subtype, message: "+element )
//						}
//					} else if ( SensorID == 9 ) {
//						if ( MessageType == MessageTypeIsSet && MessageSubType == V_TEMP ) {	// If this is:
//							// sensor value set message
//							// and
//							// message is of V_TEMP type
//							postUpdate( InsideTempFireplacePanel, Message )
//						} else {
//							postUpdate( ForDebug, "This sould have never happened! Node ID = 3, undecode message type/subtype, message: "+element )
//						}
//					}
//				else postUpdate( ForDebug, "This sould have never happened! Node ID = 3, decode not implemented for that sensor yet. Message: "+element )
			}
			case 4: { // Node ID = 4 is Attic NE
				// SHOULD decode initialistion and state set/request messages
				switch SensorID {
					case 0: { // Sensor ID = 0 is LED dimmer for Light_O_CLEDs_NE_Triangle
						if ( MessageType == MessageTypeIsSet &&
							MessageSubType == V_PERCENTAGE && Light_O_CLEDs_NE_Triangle_status == 1
						) { // If this is:
							// sensor value set message
							// and
							// message is of V_PERCENTAGE type
							if ( Light_O_CLEDs_NE_Triangle_NEW != Message ) { 
								postUpdate( Light_O_CLEDs_NE_Triangle, Light_O_CLEDs_NE_Triangle_OLD)
								}
								else {
									postUpdate( Light_O_CLEDs_NE_Triangle, Light_O_CLEDs_NE_Triangle_NEW )
								}
							Light_O_CLEDs_NE_Triangle_OLD = Message
							Light_O_CLEDs_NE_Triangle_status = 0
						} else if ( MessageType == MessageTypeIsSet &&
							MessageSubType == V_STATUS
						) { // If this is:
							// sensor value set message
							// and
							// message is of V_PERCENTAGE type
							Light_O_CLEDs_NE_Triangle_status = 1
						} else if ( MessageType == MessageTypeIsSet &&
							MessageSubType == V_PERCENTAGE
						) {
						    postUpdate( Light_O_CLEDs_NE_Triangle, Light_O_CLEDs_NE_Triangle_OLD)
			  			} else
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
					}
					case 1: { // Sensor ID = 1 is LED dimmer for Light_O_CLEDs_NW_Triangle_N
						if ( MessageType == MessageTypeIsSet &&
							MessageSubType == V_PERCENTAGE && Light_O_CLEDs_NW_Triangle_N_status == 1
						) { // If this is:
							// sensor value set message
							// and
							// message is of V_PERCENTAGE type
							if ( Light_O_CLEDs_NW_Triangle_N_NEW != Message ) { 
								postUpdate( Light_O_CLEDs_NW_Triangle_N, Light_O_CLEDs_NW_Triangle_N_OLD)
								}
								else {
									postUpdate( Light_O_CLEDs_NW_Triangle_N, Light_O_CLEDs_NW_Triangle_N_NEW )
								}
							Light_O_CLEDs_NW_Triangle_N_OLD = Message
							Light_O_CLEDs_NW_Triangle_N_status = 0
						} else if ( MessageType == MessageTypeIsSet &&
							MessageSubType == V_STATUS
						) { // If this is:
							// sensor value set message
							// and
							// message is of V_PERCENTAGE type
							Light_O_CLEDs_NW_Triangle_N_status = 1
						} else if ( MessageType == MessageTypeIsSet &&
							MessageSubType == V_PERCENTAGE
						) {
						    postUpdate( Light_O_CLEDs_NW_Triangle_N, Light_O_CLEDs_NW_Triangle_N_OLD)
			  			} else
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
					}
					case 2: { // Sensor ID = 2 is LED dimmer for Light_O_CLEDs_NE_Around
						if ( MessageType == MessageTypeIsSet &&
							MessageSubType == V_PERCENTAGE && Light_O_CLEDs_NE_Around_status == 1
						) { // If this is:
							// sensor value set message
							// and
							// message is of V_PERCENTAGE type
							if ( Light_O_CLEDs_NE_Around_NEW != Message ) { 
								postUpdate( Light_O_CLEDs_NE_Around, Light_O_CLEDs_NE_Around_OLD)
								}
								else {
									postUpdate( Light_O_CLEDs_NE_Around, Light_O_CLEDs_NE_Around_NEW )
								}
							Light_O_CLEDs_NE_Around_OLD = Message
							Light_O_CLEDs_NE_Around_status = 0
						} else if ( MessageType == MessageTypeIsSet &&
							MessageSubType == V_STATUS
						) { // If this is:
							// sensor value set message
							// and
							// message is of V_PERCENTAGE type
							Light_O_CLEDs_NE_Around_status = 1
						} else if ( MessageType == MessageTypeIsSet &&
							MessageSubType == V_PERCENTAGE
						) {
						    postUpdate( Light_O_CLEDs_NE_Around, Light_O_CLEDs_NE_Around_OLD)
			  			} else
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
					}
					case 3: { // Sensor ID = 3 is TEMP36 temperature sensor (in the box)
						if ( MessageType == MessageTypeIsSet && MessageSubType == V_TEMP ) { // If this is:
							// sensor value set message
							// and
							// message is of V_TEMP type
							postUpdate(InsideTempAtticNEBox, Message)
// just for test sendCommand(Arduino, "1;2;1;0;5;stable\n")
						} else {
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
						}
					}
					case 255: { // Sensor ID = 255 is service ID
							postUpdate( ForDebug, "This is a service message: "+element )
					}
					default: postUpdate( ForDebug, "This sould have never happened! Node ID = 4, undefined Sensor ID encountered. Message: "+element )
				}
			}
			case 5: { // Node ID = 5 is Attic SW
				
				switch SensorID {
					case 0: { // Sensor ID = 0 is LED dimmer for Light_O_CLEDs_SW_Triangle
				//	postUpdate( ForDebug, "Listed: "+element )
						if ( MessageType == MessageTypeIsSet &&
							MessageSubType == V_PERCENTAGE && Light_O_CLEDs_SW_Triangle_status == 1
						) { // If this is:
							// sensor value set message
							// and
							// message is of V_PERCENTAGE type
				//			postUpdate( ForDebug, "Comparison is: "+ Message + " - NEW: " + Light_O_CLEDs_SW_Triangle_NEW)
							if ( Light_O_CLEDs_SW_Triangle_NEW != Message ) { 
								postUpdate( Light_O_CLEDs_SW_Triangle, Light_O_CLEDs_SW_Triangle_OLD)
								}
								else {
									postUpdate( Light_O_CLEDs_SW_Triangle, Light_O_CLEDs_SW_Triangle_NEW )
								}
				//			postUpdate( ForDebug, "Light_O_CLEDs_SW_Triangle_OLD is: "+ Light_O_CLEDs_SW_Triangle_OLD )
				//			postUpdate( ForDebug, "Light_O_CLEDs_SW_Triangle_status is: "+ Light_O_CLEDs_SW_Triangle_status )
							Light_O_CLEDs_SW_Triangle_OLD = Message
				//			postUpdate( ForDebug, "Light_O_CLEDs_SW_Triangle_OLD 2 is: "+ Light_O_CLEDs_SW_Triangle_OLD )
							Light_O_CLEDs_SW_Triangle_status = 0
						} else if ( MessageType == MessageTypeIsSet &&
							MessageSubType == V_STATUS
						) { // If this is:
							// sensor value set message
							// and
							// message is of V_PERCENTAGE type
							Light_O_CLEDs_SW_Triangle_status = 1
				//			postUpdate( ForDebug, "SET status. THIS is here: "+element )
						} else {
						    postUpdate( Light_O_CLEDs_SW_Triangle, Light_O_CLEDs_SW_Triangle_OLD)
			  //		    postUpdate( ForDebug, "THIS is here 3: "+element )
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
							}
					}
					case 1: { // Sensor ID = 1 is LED dimmer for Light_O_CLEDs_NW_Triangle_W
						if ( MessageType == MessageTypeIsSet &&
							MessageSubType == V_PERCENTAGE && Light_O_CLEDs_NW_Triangle_W_status == 1
						) { // If this is:
							// sensor value set message
							// and
							// message is of V_PERCENTAGE type
							if ( Light_O_CLEDs_NW_Triangle_W_NEW != Message ) { 
								postUpdate( Light_O_CLEDs_NW_Triangle_W, Light_O_CLEDs_NW_Triangle_W_OLD)
								}
								else {
									postUpdate( Light_O_CLEDs_NW_Triangle_W, Light_O_CLEDs_NW_Triangle_W_NEW )
								}
							Light_O_CLEDs_NW_Triangle_W_OLD = Message
							Light_O_CLEDs_NW_Triangle_W_status = 0
						} else if ( MessageType == MessageTypeIsSet &&
							MessageSubType == V_STATUS
						) { // If this is:
							// sensor value set message
							// and
							// message is of V_PERCENTAGE type
							Light_O_CLEDs_NW_Triangle_W_status = 1
						} else if ( MessageType == MessageTypeIsSet &&
							MessageSubType == V_PERCENTAGE
						) {
						    postUpdate( Light_O_CLEDs_NW_Triangle_W, Light_O_CLEDs_NW_Triangle_W_OLD)
			  			} else
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
					}
					case 2: { // Sensor ID = 0 is LED dimmer for Light_O_CLEDs_SW_Around
						if ( MessageType == MessageTypeIsSet &&
							MessageSubType == V_PERCENTAGE && Light_O_CLEDs_SW_Around_status == 1
						) { // If this is:
							// sensor value set message
							// and
							// message is of V_PERCENTAGE type
							if ( Light_O_CLEDs_SW_Around_NEW != Message ) { 
								postUpdate( Light_O_CLEDs_SW_Around, Light_O_CLEDs_SW_Around_OLD)
								}
								else {
									postUpdate( Light_O_CLEDs_SW_Around, Light_O_CLEDs_SW_Around_NEW )
								}
							Light_O_CLEDs_SW_Around_OLD = Message
							Light_O_CLEDs_SW_Around_status = 0
						} else if ( MessageType == MessageTypeIsSet &&
							MessageSubType == V_STATUS
						) { // If this is:
							// sensor value set message
							// and
							// message is of V_PERCENTAGE type
							Light_O_CLEDs_SW_Around_status = 1
						} else if ( MessageType == MessageTypeIsSet &&
							MessageSubType == V_PERCENTAGE
						) {
						    postUpdate( Light_O_CLEDs_SW_Around, Light_O_CLEDs_SW_Around_OLD)
			  			} else
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
					}
					case 3: { // Sensor ID = 3 is TEMP36 temperature sensor (in the box)
						if ( MessageType == MessageTypeIsSet && MessageSubType == V_TEMP ) { // If this is:
							// sensor value set message
							// and
							// message is of V_TEMP type
							postUpdate(InsideTempAtticSWBox, Message)
						} else {
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
						}
					}
					case 4: { // Sensor ID = 4 is TEMP36 temperature sensor (outside box)
						if ( MessageType == MessageTypeIsSet && MessageSubType == V_TEMP ) { // If this is:
							// sensor value set message
							// and
							// message is of V_TEMP type
							postUpdate(InsideTempAtticSW, Message)
						} else {
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
						}
					}
					case 255: { // Sensor ID = 255 is service ID
							postUpdate( ForDebug, "This is a service message: "+element )
					}
					default: postUpdate( ForDebug, "This sould have never happened! Node ID = 5, undefined Sensor ID encountered. Message: "+element )
				}
			}
			case 6: { // Node ID = 6 is Outside light sensor
				
				switch SensorID {
					case 0: { // Sensor ID = 0 is TSL2561 light sensor
						if ( MessageType == MessageTypeIsSet && MessageSubType == V_LIGHT_LEVEL ) { // If this is:
							// sensor value set message
							// and
							// message is of V_LIGHT_LEVEL type, NOTE that wron type is used, V_LEVEL and S_LIGHT_LEVEL should be used
							postUpdate(OutsideLight, Message)
						} else {
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
						}
					}
					case 255: { // Sensor ID = 255 is service ID
							postUpdate( ForDebug, "This is a service message: "+element )
					}
					default: postUpdate( ForDebug, "This sould have never happened! Node ID = 6, undefined Sensor ID encountered. Message: "+element )
				}
			}
			case 7: { // Node ID = 7 is repeater node
				
				switch SensorID {
					case 0: { // Sensor ID = 0 is TEMP36 temperature sensor (in the box)
						if ( MessageType == MessageTypeIsSet && MessageSubType == V_TEMP ) { // If this is:
							// sensor value set message
							// and
							// message is of V_TEMP type
							postUpdate( InsideTempRepeaterNode, Message )
						} else {
							postUpdate( ForDebug, "This sould have never happened! Unknown message: "+element )
						}
					}
					case 255: { // Sensor ID = 255 is service ID
							postUpdate( ForDebug, "This is a service message: "+element )
					}
					default: postUpdate( ForDebug, "This sould have never happened! Node ID = 7, undefined Sensor ID encountered. Message: "+element )
				}
			}
			case 254: { // Node ID = 254 is test node
				
				postUpdate( ForDebug, "Test node. Node ID = 254. Message: "+element )
			}

			default: postUpdate( ForDebug, "This sould have never happened! Undefined Node ID encountered. Message: "+element )
		}
	}

end

@jtupulis Hi Janis, I was in a similar situation; long-term v1 user, then v2… did not adopt the new actions and remained on v1 bindings. THen OH3 cam a long, and I pushed out the migration as long as I could… too many new things, lots of stuff doing my head in.

Wanting to continue to use OH, I eventually had no choice but to migrate to OH3, based on the following drivers:

  1. support for versions earlier than OH3 was waning
  2. I wanted to use a new binding which was only available in OH3
  3. and conceded that not upgrading will stifle my automation attempts of newer things.

The way I went about migrating was then and in hindsight simple:

  1. I got another Raspberry Pi and installed openHABian on it; main reason being: this is fully supported
  2. I started migrating my items in sections one by one; e.g. temperature sensors; irrigation, etc. – in conjunction with the related rules
  3. I migrated the rules related to the items
  4. I created the required thing; I had never used the UI (all OH pre v3 was text-based)

These four steps involved a lot of reading the docs. I think I had ten-ish posts about making things work. E.g. date format-related, execCommand, and other I can’t recall now.
Once I started with a couple of (item) “sections”, I got more comfortable, and did multiple sections over the course of a months, if not two.
The benefits is: no rush, as I was working in parallel.

I did not set-up a MQTT broker, and simply connected to the existing on on the OH2 system.
I commented out any updates to any MQTT items.

Doing it this way, I could commands/state updates being received, and actioned, just not published to the real device.

I eventually had recreated 40 things, 940 items and 150 rules.
After motoring this for a few days, I installed the MQTT broker on OH3.
… switched off OH2, changed the IP address on OH3 to the OH2 IP
… switched on OH3 and all was running just fine… most of it.

I later discovered that I missed some transformations, did forget to include the odd item in a group, or did not persist the odd items; all easily resolvable.

This was last year Nov/Dec… running OH3 since late Dec 2022. Have since forgotten all the associated pain, and am happy I did migrate.

I can only encourage you to do the same. Take your time. I often do not touch my system for many months, and due to the long pauses in-between, I completely forget how the commands and how all works, having to look up existing items, things, rules, to create new ones.

4 Likes

FWIW the Modbus binding has a Thing type to represent bits
Mappping that to a switch item is a sleeker, language independent solution.

1 Like

Which type it is?