Posts: 20 
	Threads: 6 
	Joined: Jan 2020
	
 Reputation: 
 0
	 
 
	
	
		Hi,  
Has anyone collected practical experiences with IoT-Devices from  Shelly - particularly controlling them from KNX via LM5?
 
e.g.: interesting applications are mainly in budget-sensitive environments:  
- Power-measurement with  LM3 for visualisation and triggering event based actions  
- Using the  Shelly i3 as a wireless-KNX-sensor in a retrofit environment 
- Using the  Shelly RGBW2 as a KNX to WiFi-RGBW-LED-dimmer in a retrofit environment 
... to name a few
 
Thanks
	  
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 8422 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
 481
	 
 
	
	
		This can be implemented either by using MQTT broker in LM (two-way) or HTTP (remote services to LM, HTTP requests from LM scripts).
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 20 
	Threads: 6 
	Joined: Jan 2020
	
 Reputation: 
 0
	 
 
	
		
		
		28.11.2020, 14:31 
(This post was last modified: 28.11.2020, 14:40 by Todayslife.)
		
	 
	
		 (24.11.2020, 13:35)admin Wrote:  This can be implemented either by using MQTT broker in LM (two-way) or HTTP (remote services to LM, HTTP requests from LM scripts). Thanks for the very quick reply :-)
 
Very well so far, using the MQTT Broker in LM5 sounds indeed promising.  
Therefor, one might be really happy getting a more specific answer to the original question; in particular about actual practical experiences - if any exists already - in terms of how to integrate Shelly' IoT-Devices within the LogicMachine's "ecosystem".  
(eg. using the LM5's new MQTT Broker). 
 
Hence, trying to precise above question as follows (and please excuse, if this may sound amateurish):  
"Has anyone already made  practical experiences with IoT-Devices from Shelly? In particular; successfully controlling Shelly-Devices from the KNX-bus via LM5's MQTT Broker"?
 
Thanks again
	  
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 8422 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
 481
	 
 
	
	
		I don't think that anybody has made an integration yet but it's very easy to do. On LM side you need to enable broker and create a script to exchange values between MQTT and LM objects. On Shelly device you need to set MQTT broker address and topic.
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 20 
	Threads: 6 
	Joined: Jan 2020
	
 Reputation: 
 0
	 
 
	
		
		
		28.11.2020, 15:41 
(This post was last modified: 28.11.2020, 15:42 by Todayslife.)
		
	 
	
		 (28.11.2020, 14:55)admin Wrote:  I don't think that anybody has made an integration yet but it's very easy to do. On LM side you need to enable broker and create a script to exchange values between MQTT and LM objects. On Shelly device you need to set MQTT broker address and topic. Thank you for the - again - quick response. 
   
Well, just enabling the MQTT-Broker on the LM5 (SW: 20200720) wasn't bringing up much questions as it seemed.  
So it appeared as easy on the Shelly-Device to set the MQTT broker's address and topic.
 
Whereis - for someone being unexperienced and feeling rather uncomfortable writing software - creating a script to exchange values between MQTT and LM objects seems indeed much more troublesome - hence, please excuse, if asking for your help in writing such scripts may try your patience.
   
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 8422 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
 481
	 
 
	
	
		See this thread for a fully working script with two-way exchange between LM objects and MQTT:  https://forum.logicmachine.net/showthrea...6#pid10926
You need to set the broker address to 127.0.0.1 and edit mqtt_to_object/object_to_mqtt tables. Make sure that you don't have the same topic mapped to both tables otherwise you can get a loop.
	  
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 21 
	Threads: 5 
	Joined: Oct 2020
	
 Reputation: 
 0
	 
 
	
	
		Sorry, but I'm not able to use the script. 
 
I changed the broker address with 127.0.0.1 (local borker) and modified the mqtt_to_object/object_to_mqtt tables in order to do a simple ON /OFF of an mqtt object (shelly) as example. 
 
My tables has: 
mqtt_to_object = { 
['shellies/shellyplug-s-??????/relay/0'] = '0/0/12'  
} 
 
where 0/0/12 is the On/Off knx status 
and 
 
object_to_mqtt = { 
    ['0/0/11'] = 'shellies/shellyplug-s-??????/relay/0/command' 
  } 
 
 
where 0/0/11 is the On/Off knx command 
 
Shelly want on and off command, not 0 or 1. I used custom value to modify that, but doesn't work 
 
Here is my log: 
* arg: 1 
  * string: mqtt connect status 
* arg: 2 
  * bool: true 
* arg: 3 
  * number: 0 
* arg: 4 
  * string: connection accepted 
* arg: 5 
  * number: 0 
* arg: 6 
  * nil 
 
 
Thank you
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 8422 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
 481
	 
 
	
	
		Modify the script around line 108, change this: 
Code: if type(value) == 'boolean' then 
  value = value and 1 or 0 
end
 
To this:
 Code: if type(value) == 'boolean' then 
  value = value and 'on' or 'off' 
end
 
Also make sure that Shelly MQTT address is not 127.0.0.1 but LM IP address.
	  
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 21 
	Threads: 5 
	Joined: Oct 2020
	
 Reputation: 
 0
	 
 
	
		
		
		26.12.2020, 21:32 
(This post was last modified: 26.12.2020, 21:36 by mdisilvestro.)
		
	 
	
		Thanks, but something is wrong. 
Here is my script:
 Code: if not broker then 
  broker = '127.0.0.1' 
 
  function multiply(mult) 
    return function(value) 
      local num = tonumber(value) 
      if num then 
        return num * mult 
      else 
        return value 
      end 
    end 
  end 
 
  -- topic to object map 
  mqtt_to_object = { 
    ['shellies/shellyplug-s-?????/relay/0'] = '3/0/2' 
  } 
 
  -- optional topic value conversion function 
 -- mqtt_to_object_conv = { 
 --   ['in/topic1'] = multiply(100), 
  --  ['in/topic2'] = multiply(0.01), 
 -- } 
 
  -- object to topic map 
  object_to_mqtt = { 
    ['3/0/3'] = 'shellies/shellyplug-s-??????/relay/0/command' 
  } 
 
  datatypes = {} 
 
  grp.sender = 'mq' 
  require('socket') 
 
  for addr, _ in pairs(object_to_mqtt) do 
    local obj = grp.find(addr) 
    if obj then 
      datatypes[ addr ] = obj.datatype 
    end 
  end 
 
  mclient = require('mosquitto').new() 
 
  mclient.ON_CONNECT = function(res, ...) 
    log('mqtt connect status', res, ...) 
 
    if res then 
      for topic, _ in pairs(mqtt_to_object) do 
        mclient:subscribe(topic) 
      end 
    else 
      mclient:disconnect() 
    end 
  end 
 
  mclient.ON_MESSAGE = function(mid, topic, payload) 
    local addr = mqtt_to_object[ topic ] 
    if addr then 
      local fn = mqtt_to_object_conv[ topic ] 
 
      if fn then 
        payload = fn(payload) 
      end 
 
      grp.write(addr, payload) 
    end 
  end 
 
  mclient.ON_DISCONNECT = function(...) 
    log('mqtt disconnect', ...) 
    mclientfd = nil 
  end 
 
  function mconnect() 
    local fd 
 
    mclient:connect(broker) 
    fd = mclient:socket() 
 
    -- fd ref is valid 
    if fd then 
      mclientfd = fd 
    end 
  end 
 
  mconnect() 
 
  function publishvalue(event) 
    -- message from us or client is not connected 
    if event.sender == 'mq' or not mclientfd then 
      return 
    end 
 
    local addr = event.dst 
    local dpt = datatypes[ addr ] 
    local topic = object_to_mqtt[ addr ] 
 
    -- unknown object 
    if not dpt or not topic then 
      return 
    end 
 
    local value = busdatatype.decode(event.datahex, dpt) 
    if value ~= nil then 
      if type(value) == 'boolean' then 
        value = value and 'on' or 'off' 
      end 
 
      mclient:publish(topic, tostring(value)) 
    end 
  end 
 
  lbclient = require('localbus').new(1) 
  lbclient:sethandler('groupwrite', publishvalue) 
 
  lbclientfd = socket.fdmaskset(lbclient:getfd(), 'r') 
 
  -- run timer every 5 seconds 
  timer = require('timerfd').new(5) 
  timerfd = socket.fdmaskset(timer:getfd(), 'r') 
end 
 
-- mqtt connected 
if mclientfd then 
  mclientfdset = socket.fdmaskset(mclientfd, mclient:want_write() and 'rw' or 'r') 
  res, lbclientstat, timerstat, mclientstat = 
      socket.selectfds(10, lbclientfd, timerfd, mclientfdset) 
-- mqtt not connected 
else 
  res, lbclientstat, timerstat = 
    socket.selectfds(10, lbclientfd, timerfd) 
end 
 
if mclientfd and mclientstat then 
  if socket.fdmaskread(mclientstat) then 
    mclient:loop_read() 
  end 
 
  if socket.fdmaskwrite(mclientstat) then 
    mclient:loop_write() 
  end 
end 
 
if lbclientstat then 
  lbclient:step() 
end 
 
if timerstat then 
  -- clear armed timer 
  timer:read() 
 
  if mclientfd then 
    mclient:loop_misc() 
  else 
    mconnect() 
  end 
end
 
LOG1: 
* arg: 1 
  * string: mqtt connect status 
* arg: 2 
  * bool: false 
* arg: 3 
  * number: 5 
* arg: 4 
  * string: connection refused - not authorized 
* arg: 5 
  * number: 0 
* arg: 6 
  * nil
 
LOG2: 
* arg: 1 
  * string: mqtt disconnect 
* arg: 2 
  * bool: false 
* arg: 3 
  * number: 0 
* arg: 4 
  * string: unexpected disconnect 
* arg: 5 
  * nil
 
logging continusly, every 10 seconds
 
Shelly use correct LM IP for broker device. The MQTT communication works fine, I tested it whit MQTT.fx software.
 
Simplifing: I want that an "ON" knx telegram became ad an "ON" request through mqtt, and viceversa.
 
Thanks
	  
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 8422 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
 481
	 
 
	
	
		Are you able to control your Shelly device using an external MQTT client? You can monitor what LM is writing to these topics and check what's wrong. The last change will publish on/off for binary objects.
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 102 
	Threads: 16 
	Joined: Aug 2019
	
 Reputation: 
 0
	 
 
	
	
		Hello, 
I also have a problem with the shelly connection and I don't know what I'm doing wrong. Please if anyone can help.
 LM Mqtt broker
MQTT explorer
Code: if not broker then 
  broker = '127.0.0.1' 
 
  function multiply(mult) 
    return function(value) 
      local num = tonumber(value) 
      if num then 
        return num * mult 
      else 
        return value 
      end 
    end 
  end 
 
  -- topic to object map 
  mqtt_to_object = { 
    ['shellies/shellyplug-s-D9AA39/relay/0'] = '32/1/1', 
    ['shellies/shellyplug-s-D9AA39/temperature'] = '32/1/2', 
  } 
 
-- optional topic value conversion function 
 mqtt_to_object_conv = { 
  ['shellies/shellyplug-s-D9AA39/relay/0'] = multiply(1), 
   ['shellies/shellyplug-s-D9AA39/temperature'] = multiply(1), 
 } 
 
  -- object to topic map 
object_to_mqtt = { 
   -- ['1/1/1'] = 'out/topic1', 
   -- ['1/1/2'] = 'out/topic2', 
  } 
 
  datatypes = {} 
 
  grp.sender = 'mq' 
  require('socket') 
 
  for addr, _ in pairs(object_to_mqtt) do 
    local obj = grp.find(addr) 
    if obj then 
      datatypes[ addr ] = obj.datatype 
    end 
  end 
 
  mclient = require('mosquitto').new() 
 
  mclient.ON_CONNECT = function(res, ...) 
    log('mqtt connect status', res, ...) 
 
    if res then 
      for topic, _ in pairs(mqtt_to_object) do 
        mclient:subscribe(topic) 
      end 
    else 
      mclient:disconnect() 
    end 
  end 
 
  mclient.ON_MESSAGE = function(mid, topic, payload) 
    local addr = mqtt_to_object[ topic ] 
    if addr then 
      local fn = mqtt_to_object_conv[ topic ] 
 
      if fn then 
        payload = fn(payload) 
      end 
 
      grp.write(addr, payload) 
    end 
  end 
 
  mclient.ON_DISCONNECT = function(...) 
    log('mqtt disconnect', ...) 
    mclientfd = nil 
  end 
 
  function mconnect() 
    local fd 
 
    mclient:connect(broker) 
    fd = mclient:socket() 
 
    -- fd ref is valid 
    if fd then 
      mclientfd = fd 
    end 
  end 
 
  mconnect() 
 
  function publishvalue(event) 
    -- message from us or client is not connected 
    if event.sender == 'mq' or not mclientfd then 
      return 
    end 
 
    local addr = event.dst 
    local dpt = datatypes[ addr ] 
    local topic = object_to_mqtt[ addr ] 
 
    -- unknown object 
    if not dpt or not topic then 
      return 
    end 
 
    local value = busdatatype.decode(event.datahex, dpt) 
    if value ~= nil then 
      if type(value) == 'boolean' then 
        value = value and 1 or 0 
      end 
 
      mclient:publish(topic, tostring(value)) 
    end 
  end 
 
  lbclient = require('localbus').new(1) 
  lbclient:sethandler('groupwrite', publishvalue) 
 
  lbclientfd = socket.fdmaskset(lbclient:getfd(), 'r') 
 
  -- run timer every 5 seconds 
  timer = require('timerfd').new(5) 
  timerfd = socket.fdmaskset(timer:getfd(), 'r') 
end 
 
-- mqtt connected 
if mclientfd then 
  mclientfdset = socket.fdmaskset(mclientfd, mclient:want_write() and 'rw' or 'r') 
  res, lbclientstat, timerstat, mclientstat = 
      socket.selectfds(10, lbclientfd, timerfd, mclientfdset) 
-- mqtt not connected 
else 
  res, lbclientstat, timerstat = 
    socket.selectfds(10, lbclientfd, timerfd) 
end 
 
if mclientfd and mclientstat then 
  if socket.fdmaskread(mclientstat) then 
    mclient:loop_read() 
  end 
 
  if socket.fdmaskwrite(mclientstat) then 
    mclient:loop_write() 
  end 
end 
 
if lbclientstat then 
  lbclient:step() 
end 
 
if timerstat then 
  -- clear armed timer 
  timer:read() 
 
  if mclientfd then 
    mclient:loop_misc() 
  else 
    mconnect() 
  end 
end
  
LM log
LM Objects
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 8422 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
 481
	 
 
	
	
		Add logging to ON_MESSAGE to check that you are getting the data. Also do a full script restart the script via disable/enable. 
Code: mclient.ON_MESSAGE = function(mid, topic, payload) 
    local addr = mqtt_to_object[ topic ] 
 
    log('message', topic, payload, addr) 
 
    if addr then 
      local fn = mqtt_to_object_conv[ topic ] 
 
      if fn then 
        payload = fn(payload) 
      end 
 
      log('write', addr, payload) 
 
      grp.write(addr, payload) 
    end 
  end
  
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 102 
	Threads: 16 
	Joined: Aug 2019
	
 Reputation: 
 0
	 
 
	
	
		 (22.06.2022, 09:27)admin Wrote:  Add logging to ON_MESSAGE to check that you are getting the data. Also do a full script restart the script via disable/enable. 
Code:   mclient.ON_MESSAGE = function(mid, topic, payload) 
    local addr = mqtt_to_object[ topic ] 
 
    log('message', topic, payload, addr) 
 
    if addr then 
      local fn = mqtt_to_object_conv[ topic ] 
 
      if fn then 
        payload = fn(payload) 
      end 
 
      log('write', addr, payload) 
 
      grp.write(addr, payload) 
    end 
  end
  nothing different is logged..
 Code: * arg: 1 
  * string: mqtt connect status 
* arg: 2 
  * bool: true 
* arg: 3 
  * number: 0 
* arg: 4 
  * string: connection accepted 
* arg: 5 
  * number: 0 
* arg: 6 
  * nil
  
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 8422 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
 481
	 
 
	
	
		The same script works for me when sending messages from MQTT explorer. Do you have "Allow anonymous connection" enabled in MQTT broker configuration on LM? If not then you need to specify the login/password in the script.  
Modify the script around line 45 by adding login_set call and restart it via disable/enable:
 Code: mclient = require('mosquitto').new() 
mclient:login_set('test', '123456')
  
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 102 
	Threads: 16 
	Joined: Aug 2019
	
 Reputation: 
 0
	 
 
	
		
		
		29.06.2022, 13:45 
(This post was last modified: 30.06.2022, 08:21 by a455115.)
		
	 
	
		Hello admin! 
 
I did it and my script is already working! I still didn't understand where the problem was. I returned the original settings to LM, I wrote the same script and it already works! 
Thanks again for your help and time
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 102 
	Threads: 16 
	Joined: Aug 2019
	
 Reputation: 
 0
	 
 
	
		
		
		30.06.2022, 15:12 
(This post was last modified: 30.06.2022, 15:14 by a455115.)
		
	 
	
		I have another problem. The value I take from shelly is string, how do I convert it so I can use it as int or bool? And is there a way to add all the shelly functions to a library and call them only by name and serial number?
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 8422 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
 481
	 
 
	
	
		You can write a custom conversion function and add it to mqtt_to_object_conv table. What kind of string value is it?
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 8422 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
 481
	 
 
	
	
		In case somebody else needs this, here's an example that logs all messages for all topics from the local broker. If anonymous access is disabled then remove the comment (--) from line 23 and set username and password as needed. 
Code: broker = '127.0.0.1' 
 
mclient = require('mosquitto').new() 
 
mclient.ON_CONNECT = function(res, ...) 
  log('mqtt connect status', res, ...) 
 
  if res then 
    mclient:subscribe('#') 
  else 
    mclient:disconnect() 
  end 
end 
 
mclient.ON_MESSAGE = function(mid, topic, payload) 
  log('mqtt message', topic, payload) 
end 
 
mclient.ON_DISCONNECT = function(...) 
  log('mqtt disconnect', ...) 
end 
 
-- mclient:login_set('test', '123456') 
 
mclient:connect(broker) 
mclient:loop_forever() 
 
os.sleep(1)
  
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 102 
	Threads: 16 
	Joined: Aug 2019
	
 Reputation: 
 0
	 
 
	
	
		 (30.06.2022, 15:19)admin Wrote:  You can write a custom conversion function and add it to mqtt_to_object_conv table. What kind of string value is it? 
It returns me an On / Off value but as a string.
	  
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 8422 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
 481
	 
 
	
	
		Add before  multiply function:
 Code: function onofftobool(payload) 
  return tostring(payload):lower() == 'on' 
end
 
Then modify  mqtt_to_object_conv table:
 Code: mqtt_to_object_conv = { 
  ['shellies/shellyplug-s-D9AA39/relay/0'] = onofftobool, 
}
  
	 
	
	
	
		
	 
 
 
	 
 |