MODBUS and System air

modbus
Tags: #<Tag:0x00007f0145be3438>

(Kim Skatun) #1

Hi
I got this system air ventilation now and I would like to get it hooked up to the openhab. It uses modbus protocol, and to be honest I have never dealt with modbus before.

So I figure out I need to set this in configuaration.cfg

modbus:serial.slave1.connection=/dev/ttyUSB0
modbus:tcp.slave1.length=10
modbus:tcp.slave1.type=coil

So as a start I would just like to read out the fanspeed:

Full manual can be found here

So should my number item look like this?

Number Dimmer1 “Dimmer1 [%d]” (ALL) {modbus=“slave1:101”}

And how can I write to it?

What i want to be able to in the end is to regulate the fan speed dependent on my number Item CO2, which tells me the CO2 level in my level.

Any tips to point me in the right direction would be great


(Marcin) #2

Hi Kim !

I have same problem, but with diff ventilation system (Thessla), I got very similar instruction list from a vendor and I have no clue how to deploy it with modbus binding.

My first plan is to obtain connectivity between raspberry and Thessla via USB -RS485 adaptor. I have seen few description how to config it and how to send a commends. Then I will try to do some tests with binding.


(Kim Skatun) #3

Great, there is also a binding out there for another hvac system, maybe we can get some hint from that:)


(moskovskiy82) #4

What did you use to connect the systemair to openhab?


(Mbs38) #5

The Register 101 does not contain a number. It is just 5 boolean values interpreted and transmitted as a 16bit integer/register. Modbus registers are always 16bit in size.

Considering this:

“5
Coils and digital inputs are always available as register as well. The address of the coil or digital input
can be calculated as follows:
Address – (Register Address * 16) – 15”
=> 101*16 - 15 = 1601
you should therefore try to read coils 1601 to 1606:

in openhab.cfg:
modbus:serial.slave1.connection=/dev/ttyUSB0:9600:8:none:1:rtu
modbus:serial.slave1.id=1
modbus:serial.slave1.start=1601
modbus:serial.slave1.length=5
modbus:serial.slave1.type=coil

in .items:
Switch FansOff { modbus=“slave1:0” }
Switch FansOnLowSpeed { modbus=“slave1:1” }
and so on…

Good Luck :sunglasses:


(Kim Skatun) #6

I guess it should say Address = (Register Address * 16) – 15 , but I don’t get why minus 15 and the factor 16 is because it 16 bits values, so basically we are trying to read out value 101, which is 00000000 01100101 in binary. So i guess the binding sends that value and back it gets a value which is between 0 and 4 (5 values). And if I am correct this is also a 16 bit value, lets say 2: 00000000 00000010

Then how does the binding differentiate between reading and writing?
Switch FansOnHighSpeed { modbus=“slave1:3” }

But how can we define it the other way:
Number FanSpeed{modbus=slave1}

And also

modbus:serial.slave1.id=1
modbus:serial.slave1.start=1616
modbus:serial.slave1.length=4
modbus:serial.slave1.type=coil

Do you need to do this for every register you need to set in the config file? Seems like it would be better to set it in the itemfile for each of the item.

Well I am a newbie to hvac and modbus but it seems like that the fan speed should be set to match the co2 level:

How often should the rule update the fan speed? And should you set fan speed different for exhaust and supply, and would you do a simple proportional regulator? Like try to keep CO2 level at 800PPM? Like

rule 'set fanspeed'

when cron ???? //5 min??

val error =  co2Item-800
if error<0
    sendCommand(fan,off)
else
     kp=50 //A factor that needs to be tested
     sendCommand(fanSpeed,error*kp)
end if

(Mbs38) #7

Sure.

This is totally vendor specific. This is just the way they implemented it.

Not really. When reading coils there is no need to read them in chunks of 16 bits. Consider the Modbus data type…:

From this line modbus:serial.slave1.type=coil it knows that everything in slave1 is a coil and therefore writable.
In Modbus there are two data types: booleans (discretes and coils) and 16bit registers (holding registers, input registers).
Coils and holding registers are read/writeable, discretes and input registers are readonly.

[quote=“skatun, post:6, topic:6212”]
How often should the rule update the fan speed? And should you set fan speed different for exhaust and supply, and would you do a simple proportional regulator? Like try to keep CO2 level at 800PPM? Like
[/quote] Sorry, no idea. I know nothing about ventilation systems. All I did was read through that pdf an make an educated guess based on my knowledge of Modbus and the binding. :stuck_out_tongue:
Anyway, I would execute the rule whenever the item in question is updated (by the modbus binding). So something like:
when Item xyz received update
then …

You may want to take a look at this website.

Best regards,
M


(Kim Skatun) #8

Thank you. I will test it out this week.


(Marcin) #9

I was successfully connected with Modbus using following config:

modbus:serial.slave1.connection=/dev/ttyUSB0:9600:8:even:1:rtu
modbus:serial.slave1.id=10
modbus:serial.slave1.start=0
modbus:serial.slave1.type=holding
modbus:serial.slave1.length=1

I have read some integer, but I dont know what is it :slightly_smiling:
I got similar 8 pages modbus manual for my system air. ie

Variable: date, time (4 registries must be read at once)
Description: [YYMM] [DDWW] [HHMM] [SSCC] year/month, day/week, etc
Min-max value:0-99, 1-12, 1-31, etc
BMS type: 03-HOLDING REGISTER
MODBUS INDEX: 0,1,2,3

So how to translate modbus index to “modbus:serial.slave1.start” ? Is this “start” means data address in DEC or HEX?
Also which length should be ? When I put 4 I got crc error.
Do I need to separate read each register and assign it to Number in items ?


(Mbs38) #10

For that you should read registers 0 to 3:
modbus:serial.slave1.connection=/dev/ttyUSB0:9600:8:even:1:rtu
modbus:serial.slave1.id=10
modbus:serial.slave1.start=0
modbus:serial.slave1.type=holding
modbus:serial.slave1.length=4


(Marcin) #11

Thanks mbs38,

It works !
Problem was that I tried to assigned 4xregister (16bits) to 1 number item.
Now with 4 Number it works :slightly_smiling:
One more question thus length is different and it is up of type ? Otherwise coil’s length is diff then holding.

Also if need to read diff ranges /address do I need to repeat such config with diff names ?


(Mbs38) #12

Good to hear that my comment has been helpful :slightly_smiling:

I’m sorry but I am not really sure what your questions is. Usually coils, discretes, holding and input registers contain different data. Some vendors, like System Air, have chosen to have certain registers represent the states of a set of coils. This data can therefore be read by using different types.

Yes. But you can read consecutive registers with a single configuration.


(Marcin) #13

I mean that length is not fixed, holding has diff length then coils, so such config:

modbus:tcp.slave1.length=10
modbus:tcp.slave1.type=coil

will read 10x coils (which is 1bit each), but if we have 10xholding, as I understand it is 10 x 16 bits, am I right ?

If registers are not one by one I need to add new config block in cfg (name, id, equipment, etc)


(Mbs38) #14

You are.

Yep. Sometimes it is neater to read the registers inbetween as well and simply ignore the results. Of course if the registers are too far apart or the device’s implementation has been written by a moron (like with System Air) that might not work :smiley:


(Marcin) #15

Config on Thessla Green with all data seems to be smart :slight_smile: There are 8 pages og register which I can read :), some of them are dummy due to lack of sensors or optional hardware (like extra heaters or air condition modules).
I have also found out that it is better to read long block and remain some register :slightly_smiling:
Now I must test how offten can I read data to keep server alive :slightly_smiling: From my report logs, where I am reading data from 1wire, alarm system, Modbus , etc it looks quite busy :wink:


(Serg) #16

@skatun Hello Kim! So have you finally managed how to control the fan speed? I’m choosing a ventilation system at the moment and Systemair Save line looks good to me.
Can I ask you a few questions about it?

Thanks!


(moskovskiy82) #17

By the way. As modbus seemed like a steeper curve to implement i went the easier way. MySensors arduino board with 3 relays. There is a number of digital inputs on the systemair VSR board - which you can assign to control the speed of the unit.


(Serg) #18

@moskovskiy82 What Systemair vent system do you have?


(Kim Skatun) #19

@buncker I Havent got around to it unfortunately, only thing I did was to connect it to the computer and look at values it produced. The relay option @moskovskiy82 went for seems interesting, can you show some picture and mysensor code aswell`?


(moskovskiy82) #20

It’s a standard relay code published on mysensors. Same for the pics - two double relay boards. connected to digital pins on VSR board. Works for almost 4 months already without issues. mainly use it to switch off during leave and low speed for night.
Relay 1 -on = VSR off, relay 2 on = VSR low, Relay 3 on = VSR high. All relays off = medium fan on VSR. Rule in openhab
Still integrating into modbus is a good idea. This will give temp sensors. Setiing the temp and as well control over electric reheater.

rule "VENT_SPEED"
when Item vent_rule_speed changed
then
if (vent_rule_speed.state == 0)
	{
	vent_speed_low.sendCommand(OFF)
	Thread::sleep(500)
	vent_speed_high.sendCommand(OFF)
	Thread::sleep(500)
	vent_speed_off.sendCommand(ON)
	}
else if (vent_rule_speed.state == 1) //"Ventilation Low"
	{
	vent_speed_off.sendCommand(OFF)
	Thread::sleep(500)
	vent_speed_high.sendCommand(OFF)
	Thread::sleep(500)
	vent_speed_low.sendCommand(ON)
	}
else if (vent_rule_speed.state == 2) //"Ventilation Nominal"
	{
	vent_speed_off.sendCommand(OFF)
	Thread::sleep(500)
	vent_speed_high.sendCommand(OFF)
	Thread::sleep(500)
	vent_speed_low.sendCommand(OFF)
	}
else if (vent_rule_speed.state == 3) //"Ventilation High"
	{
	vent_speed_off.sendCommand(OFF)
	Thread::sleep(500)
	vent_speed_low.sendCommand(OFF)
	Thread::sleep(500)
	vent_speed_high.sendCommand(ON)
}
end