Page 1 of 1

KNOT - modbus routing via MQTT

Posted: Mon Mar 22, 2021 5:29 pm
by iiLaw
Hi very excited about the KNOT but looking at the Docs/Application examples it appears that modbus functions as an RTU to IP client/server.
So it looks like we can't route modbus to/from MQTT/HTTPs REST ?

Thanks
Lawrence

Re: KNOT - modbus routing via MQTT

Posted: Fri Jun 18, 2021 1:10 pm
by ywilien
Can someone confirm the features around Modbus ?
It would be great to be able to listen a RTU/Modbus and publish to MQTT.

Re: KNOT - modbus routing via MQTT

Posted: Tue Aug 17, 2021 10:19 pm
by Beliy
modbus works partially. read holding register only. there is no way to get a response in high-low. answers in integer only. export data to file only.

Re: KNOT - modbus routing via MQTT

Posted: Thu Oct 28, 2021 7:14 pm
by christal87
modbus works partially. read holding register only. there is no way to get a response in high-low. answers in integer only. export data to file only.
I'm thinking on switching from generic ModBus RTU->TCP gateways to the new KNOT. RouterOS can be a great tool to protect plain ModBus/TCP traffic over public channels.
Even a more compact solution when combined into one device with the RTU to TCP gateway like the KNOT.

As of today Mikrotik's new Atlassian Confluance based documetation doesn't list ModBus commands under IoT just yet.
So if I understand correctly: when I want to read lets say a kWh value from an electricity meter that's float datatype and stored in at least two 16bit registers,
I get the output as two separate 16bit registers (on the RouterOS terminal at least). The only thing I can set is the count of registers to read and data endianness is fixed.
To get over this I might have to do some background magic on the data processing side of things to combine those into one value in the correct order.

So you say there's no option to set register type like with mbpoll (mbpoll ... -t 3:float)?
Is this the case with doing a remote client query over IP too when the KNOT is a ModBus/TCP server ?
Is this mechanism going to improve/evolve in the future?

Re: KNOT - modbus routing via MQTT

Posted: Mon Nov 08, 2021 2:34 pm
by majdichebil
I haven't even find a way to read to registers. I got poll out
Any help pls?

Re: KNOT - modbus routing via MQTT

Posted: Mon Dec 20, 2021 1:49 pm
by denissMT
Currently, MODBUS in RouterOS can display only the response/reply to function code 3 (Modbus) request (that is if Modbus "slave" device that is connected to KNOT supports "function code 3"):
https://help.mikrotik.com/docs/pages/vi ... ngRouterOS
So as long as it can be "printed" in CLI, it can be scripted and posted via MQTT.

Re: KNOT - modbus routing via MQTT

Posted: Tue May 17, 2022 10:55 am
by asiobob
Currently, MODBUS in RouterOS can display only the response/reply to function code 3 (Modbus) request (that is if Modbus "slave" device that is connected to KNOT supports "function code 3"):
https://help.mikrotik.com/docs/pages/vi ... ngRouterOS
So as long as it can be "printed" in CLI, it can be scripted and posted via MQTT.
I understand this limitation if you are scripting within RouterOS. However, can RouterOS pass function code 4 requests/responses using the RS485-TCP bridge?
Currently I'm unable to read FC4 over TCP, but I can do FC 3. When I use other non-mikrotik gateways, I can read/pass FC 4 messages, hence my question

Re: KNOT - modbus routing via MQTT

Posted: Wed May 18, 2022 3:33 pm
by asiobob
For the anyone looking into using the KNOT with MODBUS
1. the RS485 'modbus' port on the KNOT is configured in Winbox from the System/ports menu
Known Bug RouterOS v6, and versions including v7.2.3 (current stable version at the time of this post) where the parity setting of even or odd continues to behave as parity=none. If your MODBUS network uses parity=even or odd, then connectivity won't work as expected. This issue is resolved as of v7.3beta33
2. RouterOS can act as a MODBUS RS485-TCP bridge. This allows external software to connect to your modbus network over TCP/IP via the KNOT. This is enabled from the IOT/modbus menu, this menu is available in v7, and only in the CLI for v6. You should firewall access appropriately since Modbus-TCP has no security on its own.
3. The MODBUS RS485-TCP bridge supports all MODBUS function code queries and responses driven from external software
4. RouterOS itself has some modbus querying commands built in. You can write scripts to query values and pass them onto the MQTT feature.
Limitation the versions of RouterOS available at the time of this post only supports Function Code 3 querying from within RouterOS. If you need other function codes you need to enable the MODBUS RS485-TCP bridge and use external software
Hope this helps.

Re: KNOT - modbus routing via MQTT

Posted: Fri Jan 13, 2023 4:51 pm
by Chiara
@asiobob thanks for the quickstart, may I ask a little more detail to get point 4. working?

4. RouterOS itself has some modbus querying commands built in. You can write scripts to query values and pass them onto the MQTT feature.

Re: KNOT - modbus routing via MQTT

Posted: Fri Jan 13, 2023 7:54 pm
by Amm0
There are few examples in other threads. For example: viewtopic.php?p=969298&hilit=modbus#p969298

Re: KNOT - modbus routing via MQTT

Posted: Thu Jan 19, 2023 10:53 am
by Chiara
Thank you it's what I was looking for, just a few questions
1) what is the meaning of " as-value once " , it's in the official docs but got no description:
https://help.mikrotik.com/docs/pages/vi ... d=61046813

2) Anyway all of this should be put in a script and then system>scheduled, so the minimum time between each poll is 1 second?

3) is it supported only read-holding-registers or exist also a write-holding-registers?

Thanks

Re: KNOT - modbus routing via MQTT

Posted: Thu Jan 19, 2023 3:30 pm
by Amm0
1) what is the meaning of " as-value once " , it's in the official docs but got no description:
https://help.mikrotik.com/docs/pages/vi ... d=61046813
There is scripting "tips and tricks", that discuss "once":
https://wiki.mikrotik.com/wiki/Manual:S ... monitor%22

Re "as-value", If you try from the CLI, you'll notice that with "once" BUT NO "as-value":
/iot modbus read-holding-registers slave-id=0x03 num-regs=0x1 reg-addr=0x0 once
... This "prints" (outputs) to the console the values.

If you remove the "once" from above command, you'll note the it just keeps running outputting value forever. But if you need a value to continue a script, you don't want it to keep outputting values – the "once" say "get the first value and move on to next command".

If you add "as-value" to same command it will print nothing – that because it's "return the value" to a variable. So the Mikrotik example tries to show both the script usage and CLI in one command (e.g. store the output to variable via "as-value", but another command :put to output to console:
{:local output [/iot modbus read-holding-registers slave-id=0x03 num-regs=0x1 reg-addr=0x0 as-value once];:put [($output->"values")]}
So without the "once" your schedule script would run forever.


2) Anyway all of this should be put in a script and then system>scheduled, so the minimum time between each poll is 1 second?
That's the granularity of the schedule, so 1 sec.

BUT, coming back to the "once"... The read-holdiing-registers command also supports a "do=" code block which how you can continuously read the registers. Essentially instead of "once", you can use do={ # code that uses $values } - that make the command like a "infinite while loop" with the do={} part executed per the defined interval. You can make do= "not infinite" by using a timeout=1s, and if you called MQTT inside the do loop, it remote as often as values were returned. But this approach is tricky in scheduler, since it's managing the interval already. The do={} method is useful sometimes. But you want something continuously reading reliably to report to something like MQTT, the schedule at 1 seconds and using "once as-value" is pretty simple.

3) is it supported only read-holding-registers or exist also a write-holding-registers?
Docs say KNOT only support function 3, which is the read registers.

Re: KNOT - modbus routing via MQTT

Posted: Fri Jan 20, 2023 11:29 am
by Chiara
Just a note about point 3) official docs it report in packet structure: "Function Parameters - usually specifies register address, data length and data to be written in case the "write" function is used."
So I was wondering if there was some optional hidden parameters, but it's not the case.


@Amm0 many thanks for your explanations, these should be added to official docs!

Re: KNOT - modbus routing via MQTT

Posted: Mon May 15, 2023 12:53 pm
by denissMT
https://mikrotik.com/download/changelog ... lease-tree
What's new in 7.10beta5 (2023-May-09 13:38):
*) iot - added option to send Modbus function code commands directly from RouterOS (CLI only);

Meaning, that you can now script the KNOT to send function code commands to the directly connected MODBUS device, store replies as variables and send them further via MQTT or /tool fetch

Re: KNOT - modbus routing via MQTT

Posted: Tue May 30, 2023 5:56 am
by wgjhonathan
We are waiting for function 04 read input register

Re: KNOT - modbus routing via MQTT

Posted: Wed Jun 21, 2023 2:11 pm
by denissMT
As per the guide:
https://help.mikrotik.com/docs/pages/vi ... ngRouterOS
the new "transceive" function allows you to send "function=x" command. In the example, we demonstrate:
/iot modbus transceive address=1 function=3 data=20000001
But change "function=4" and that will send "read input register".

Re: KNOT - modbus routing via MQTT

Posted: Fri Jun 21, 2024 1:52 pm
by wcsnet
This is what I do to get modes to mqtt
# wcs, copyright © 2010. all rights reserved
# script version : 1.0

          :local errors 0
#
          :global gostatusXscript
          :while ($gostatusXscript = "no" ) do={
                    :delay 5s;
          }
          :set gostatusXscript "no"
#
          :do {
               :global modbusregisters {
                                             {":set tmp [/iot modbus read-holding-registers slave-id=0x01 num-regs=0x1 reg-addr=154 as-value once]";"0";"154";"grid_voltage"};
                                             {":set tmp [/iot modbus read-holding-registers slave-id=0x01 num-regs=0x1 reg-addr=192 as-value once]";"0";"192";"grid_frequency"};
                                             {":set tmp [/iot modbus read-holding-registers slave-id=0x01 num-regs=0x1 reg-addr=167 as-value once]";"0";"167";"grid_power"};

                                             {":set tmp [/iot modbus read-holding-registers slave-id=0x01 num-regs=0x1 reg-addr=183 as-value once]";"0";"183";"battery_voltage"};
                                             {":set tmp [/iot modbus read-holding-registers slave-id=0x01 num-regs=0x1 reg-addr=184 as-value once]";"0";"184";"battery_state_of_charge"};
                                             {":set tmp [/iot modbus read-holding-registers slave-id=0x01 num-regs=0x1 reg-addr=190 as-value once]";"0";"190";"battery_power"};


                                             {":set tmp [/iot modbus read-holding-registers slave-id=0x01 num-regs=0x1 reg-addr=175 as-value once]";"0";"175";"inverter_power"};
                                             {":set tmp [/iot modbus read-holding-registers slave-id=0x01 num-regs=0x1 reg-addr=164 as-value once]";"0";"164";"inverter_current"};

                                             {":set tmp [/iot modbus read-holding-registers slave-id=0x01 num-regs=0x1 reg-addr=186 as-value once]";"0";"186";"mppt_1"};
                                             {":set tmp [/iot modbus read-holding-registers slave-id=0x01 num-regs=0x1 reg-addr=187 as-value once]";"0";"187";"mppt_2"};

                                             {":set tmp [/iot modbus read-holding-registers slave-id=0x01 num-regs=0x1 reg-addr=172 as-value once]";"0";"172";"172?"};
                                        }
               :global tmp
#
               :log info "[ starting - modbus mqtt ]"
#
               :foreach register in=$modbusregisters do={
                    :log info ($register->3)
#
                    :log info ("     register:")
                    :log info ("          " . ($register->2))
#
                    :log info ("     command:")
                    :log info ("          " . ($register->0))
                    :execute ($register->0)
                    :delay 2.5s
#
                    :set ($register->1) [($tmp->"values")]
                    :log info ("     reading:")
                    :log info ("          " . ($register->1))
#
                    :log info ""
#
                    /iot mqtt publish broker="x x x x " topic=("feeds/thing-x/process-power-x/outgoing/sunsynk/" . $register->2) message=($register->1) qos=2
                 }
#
               :log info "[ ending - modbus mqtt ]"
#                    
          } on-error={
                    :set gostatusXscript "yes"
                    :log error "script failure  [ modbus mqtt ]"
          }
#
          :log info "script completed with $errors errors"
          :set gostatusXscript "yes"
          :log info " "
#