Posts: 95
Threads: 16
Joined: Aug 2019
Reputation:
0
(05.07.2022, 06:36)admin Wrote: 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,
}
Thanks!
Posts: 95
Threads: 16
Joined: Aug 2019
Reputation:
0
13.10.2022, 14:26
(This post was last modified: 13.10.2022, 14:28 by a455115.)
(20.06.2022, 13:14)a455115 Wrote: 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
Hi admin,
How do I convert directly from the code to get a specific parameter from the Json it returns? For an example of a specific topic it returns json to me
shellies/shellytrv-14B457E5C2C8/info
return
{"tmp": {"value":24.5,"units": "C","is_valid": true},"target_t":{"enabled":false,"value":22.0,"units":"C "},"temperature_offset":0.0,"bat":99}
I only want to extract from it:
target_t - value - 1/1/1
bat - 1/1/2
How can I extract only this with the above code?
Posts: 7773
Threads: 42
Joined: Jun 2015
Reputation:
447
Use this (1/1/1 is battery object, 1/1/2 is target temperature value object):
Code: mqtt_to_object = {
['shellies/shellytrv-14B457E5C2C8/info'] = '1/1/1',
}
mqtt_to_object_conv = {
['shellies/shellytrv-14B457E5C2C8/info'] = function(payload)
local data = require('json').pdecode(payload)
if type(data) == 'table' then
grp.write('1/1/2', data.target_t.value)
return data.bat
end
end
}
Posts: 95
Threads: 16
Joined: Aug 2019
Reputation:
0
(14.10.2022, 06:17)admin Wrote: Use this (1/1/1 is battery object, 1/1/2 is target temperature value object):
Code: mqtt_to_object = {
['shellies/shellytrv-14B457E5C2C8/info'] = '1/1/1',
}
mqtt_to_object_conv = {
['shellies/shellytrv-14B457E5C2C8/info'] = function(payload)
local data = require('json').pdecode(payload)
if type(data) == 'table' then
grp.write('1/1/2', data.target_t.value)
return data.bat
end
end
}
Hi admin,
Data.target_t.value does not work. This is a log from data, and from data.thermostats, how should I get the target_t ? If I have many shelits for each, should I add it this way?
Code: log (data)
["ps_mode"]
* number: 0
["thermostats"]
* table:
[1]
* table:
["tmp"]
* table:
["is_valid"]
* bool: true
["units"]
* string: C
["value"]
* number: 24.7
["pos"]
* number: 50
["target_t"]
* table:
["value_op"]
* number: 8
["enabled"]
* bool: false
["units"]
* string: C
["value"]
* number: 22
["window_open"]
* bool: false
["boost_minutes"]
* number: 0
["schedule"]
* bool: false
["schedule_profile"]
* number: 1
["fs_free"]
* number: 59376
["wifi_sta"]
* table:
["connected"]
* bool: true
["rssi"]
* number: -59
["ssid"]
* string: Project Solutions
["ip"]
* string: 10.0.5.105
["dbg_flags"]
* number: 0
["mac"]
* string: 14B457E5C2C8
["cloud"]
* table:
["connected"]
* bool: false
["enabled"]
* bool: false
["time"]
* string: 12:47
["update"]
* table:
["new_version"]
* string: 20220811-152343/v2.1.8@5afc928c
["old_version"]
* string: 20220811-152343/v2.1.8@5afc928c
["status"]
* string: unknown
["beta_version"]
* userdata: NULL
["has_update"]
* bool: false
["bat"]
* table:
["voltage"]
* number: 4.077
["value"]
* number: 99
["unixtime"]
* number: 1666000030
["ram_total"]
* number: 97280
["fw_info"]
* table:
["fw"]
* string: 20220811-152343/v2.1.8@5afc928c
["device"]
* string: shellytrv-14B457E5C2C8
["calibrated"]
* bool: true
["uptime"]
* number: 5326
["charger"]
* bool: false
["ram_free"]
* number: 22568
["actions_stats"]
* table:
["skipped"]
* number: 0
["serial"]
* number: 0
["mqtt"]
* table:
["connected"]
* bool: true
["has_update"]
* bool: false
["cfg_changed_cnt"]
* number: 0
["fs_size"]
* number: 65536
log(data.thermostats)
[1]
* table:
["tmp"]
* table:
["is_valid"]
* bool: true
["units"]
* string: C
["value"]
* number: 24.7
["pos"]
* number: 50
["target_t"]
* table:
["value_op"]
* number: 8
["enabled"]
* bool: false
["units"]
* string: C
["value"]
* number: 22
["window_open"]
* bool: false
["boost_minutes"]
* number: 0
["schedule"]
* bool: false
["schedule_profile"]
* number: 1
Posts: 7773
Threads: 42
Joined: Jun 2015
Reputation:
447
Try this:
Code: mqtt_to_object = {
['shellies/shellytrv-14B457E5C2C8/info'] = '1/1/1', -- battery level
['shellies/shellytrv-ABC/info'] = '2/1/1', -- battery level
['shellies/shellytrv-DEF/info'] = '3/1/1', -- battery level
}
function conv_therm(payload, target_t_addr)
local data = require('json').pdecode(payload)
if type(data) == 'table' then
grp.write(target_t_addr, data.thermostats[1].target_t.value)
return data.bat.value
end
end
mqtt_to_object_conv = {
['shellies/shellytrv-14B457E5C2C8/info'] = function(payload)
return conv_therm(payload, '1/1/2') -- target temp
end,
['shellies/shellytrv-ABC/info'] = function(payload)
return conv_therm(payload, '2/1/2') -- target temp
end,
['shellies/shellytrv-DEF/info'] = function(payload)
return conv_therm(payload, '3/1/2') -- target temp
end
}
Posts: 95
Threads: 16
Joined: Aug 2019
Reputation:
0
(17.10.2022, 10:00)admin Wrote: Try this:
Code: mqtt_to_object = {
['shellies/shellytrv-14B457E5C2C8/info'] = '1/1/1', -- battery level
['shellies/shellytrv-ABC/info'] = '2/1/1', -- battery level
['shellies/shellytrv-DEF/info'] = '3/1/1', -- battery level
}
function conv_therm(payload, target_t_addr)
local data = require('json').pdecode(payload)
if type(data) == 'table' then
grp.write(target_t_addr, data.thermostats[1].target_t.value)
return data.bat.value
end
end
mqtt_to_object_conv = {
['shellies/shellytrv-14B457E5C2C8/info'] = function(payload)
return conv_therm(payload, '1/1/2') -- target temp
end,
['shellies/shellytrv-ABC/info'] = function(payload)
return conv_therm(payload, '2/1/2') -- target temp
end,
['shellies/shellytrv-DEF/info'] = function(payload)
return conv_therm(payload, '3/1/2') -- target temp
end
}
It works, thanks a lot!
Posts: 95
Threads: 16
Joined: Aug 2019
Reputation:
0
What is the maximum number of objects/devices Logic Machine can work with without problems? I want to hook up an apartment complex with shelly.
Posts: 7773
Threads: 42
Joined: Jun 2015
Reputation:
447
It should handle several hundred devices.
Posts: 213
Threads: 62
Joined: May 2018
Reputation:
4
Hi, with the above code, you use broadcast topic "shellies". If I use a topic set in a device, eg a ShellyPluss1 (relay) eith add-on module, how can i sort the different values on the same topic?
I made this based on the above, but it only works on th ebinary status object, not temperature:
Code: function conv_shellyRelay(payload, numberRel, target_s_addr)
local data = require('json').pdecode(payload)
if type(data) == 'table' then
grp.write(target_s_addr, data["params"][numberRel]["output"])
log(data.bat.value)
return data.bat.value
end
end
function conv_shellyTemp(payload, numberTemp, target_t_addr)
local data = require('json').pdecode(payload)
if type(data) == 'table' then
log(data["params"][numberTemp]["tC"])
grp.write(target_t_addr, data["params"][numberTemp]["tC"])
return data.bat.value
end
end
-- topic to object map
mqtt_to_object = {
['Shelly/events/rpc'] = '33/1/8', -- Temperature 1
['Shelly/events/rpc'] = '33/1/9', -- Status relay
['Shelly/events/rpc'] = '33/1/10',-- Temperature 2
}
mqtt_to_object_conv = {
['Shelly/events/rpc'] = function(payload)
return conv_shellyTemp(payload,"temperature:100", '33/1/8')
end,
['Shelly/events/rpc'] = function(payload)
return conv_shellyTemp(payload,"temperature:101", '33/1/10')
end,
['Shelly/events/rpc'] = function(payload)
return conv_shellyRelay(payload,"switch:0", '33/1/9')
end,
}
-- object to topic map
object_to_mqtt = {
['33/1/7'] = 'Shelly/command/switch:0',
}
Posts: 7773
Threads: 42
Joined: Jun 2015
Reputation:
447
You have duplicate keys in mqtt_to_object and mqtt_to_object_conv - this won't work. If multiple devices share the same topic then you need to manually implement logic for distinguishing what kind of data is received and which object must be updated.
Posts: 213
Threads: 62
Joined: May 2018
Reputation:
4
03.01.2024, 10:26
(This post was last modified: 03.01.2024, 11:05 by tomnord.)
(03.01.2024, 10:19)admin Wrote: You have duplicate keys in mqtt_to_object and mqtt_to_object_conv - this won't work. If multiple devices share the same topic then you need to manually implement logic for distinguishing what kind of data is received and which object must be updated.
Ok, I was afraid of that. So i need to make logic that only reads topic once, and then sorts out the different values I'm looking for.
So I made a function to look up certain names in the table, is there any way to have the mqtt_to_object run without a GA attached? It will only run the first grp.write:
Code: function conv_shellyTemp(payload)
local data = require('json').pdecode(payload)
if type(data) == 'table' then
function tableHasKey(table, prefix)
for key, _ in pairs(table) do
--log(key)
if string.match(key, prefix) then
return true
end
end
return false
end
if tableHasKey(data["params"],"temperature") then
grp.write('33/1/8', data["params"]["temperature:100"]["tC"])
grp.write('33/1/10', data["params"]["temperature:101"]["tC"])
elseif
tableHasKey(data["params"],"switch") then
grp.write('33/1/9', data["params"]["switch:0"]["output"])
else
log("no data")
end
end
end
Posts: 213
Threads: 62
Joined: May 2018
Reputation:
4
(03.01.2024, 10:26)tomnord Wrote: (03.01.2024, 10:19)admin Wrote: You have duplicate keys in mqtt_to_object and mqtt_to_object_conv - this won't work. If multiple devices share the same topic then you need to manually implement logic for distinguishing what kind of data is received and which object must be updated.
Ok, I was afraid of that. So i need to make logic that only reads topic once, and then sorts out the different values I'm looking for.
So I made a function to look up certain names in the table, is there any way to have the mqtt_to_object run without a GA attached? It will only run the first grp.write:
Code: function conv_shellyTemp(payload)
local data = require('json').pdecode(payload)
if type(data) == 'table' then
function tableHasKey(table, prefix)
for key, _ in pairs(table) do
--log(key)
if string.match(key, prefix) then
return true
end
end
return false
end
if tableHasKey(data["params"],"temperature") then
grp.write('33/1/8', data["params"]["temperature:100"]["tC"])
grp.write('33/1/10', data["params"]["temperature:101"]["tC"])
elseif
tableHasKey(data["params"],"switch") then
grp.write('33/1/9', data["params"]["switch:0"]["output"])
else
log("no data")
end
end
end
Figured it out, needed to activate status sending.
But I would lik eto be able to use the GetStatus function from, it seems to be a request that does not need a input.
https://shelly-api-docs.shelly.cloud/gen...us-example
Posts: 7773
Threads: 42
Joined: Jun 2015
Reputation:
447
You can attach topic to a dummy object. If the conversion function does not return anything the grp.write won't happen anyway.
For HTTP requests search the forum, there are many examples that can be adapted.
Posts: 213
Threads: 62
Joined: May 2018
Reputation:
4
Code: ["thermostats"]
* table:
[1]
* table:
["valve_min_percent"]
* number: 0
["t_auto"]
* table:
["enabled"]
* bool: true
["target_t"]
* table:
["units"]
* string: C
["value_op"]
* number: 8
["enabled"]
* bool: true
["accelerated_heating"]
* bool: true
["value"]
* number: 7
["extra_pressure"]
* bool: false
["calibration_correction"]
* bool: true
["schedule_profile_names"]
* table:
[1]
* string: Livingroom
[2]
* string: Livingroom 1
[3]
* string: Bedroom
[4]
* string: Bedroom 1
[5]
* string: Holiday
["schedule_profile"]
* number: 1
["open_window_report"]
* bool: false
["boost_minutes"]
* number: 30
["valve_min_report"]
* number: 1
["force_close"]
* bool: false
["schedule_rules"]
* table:
[1]
* string: 0600-0123456-23
[2]
* string: 2300-0123456-18
["ext_t"]
* table:
["floor_heating"]
* bool: false
["enabled"]
* bool: true
["schedule"]
* bool: false
["temperature_offset"]
* number: 0
I am trying to write to the object "temperature_offset" but i can not get the syntax right.
"'shellies/TRV_ROM1/settings/thermostats . .. "
It is stated as a parameter in the documentation for mqtt.
https://shelly-api-docs.shelly.cloud/gen...rmostats-0
The http command is:
Code: http://10.xxx.xxx.xxx/ext_t?temp=measured t°
Posts: 7773
Threads: 42
Joined: Jun 2015
Reputation:
447
Try http://IP/settings/thermostats/0?temperature_offset=5
If this does not work then contact Shelly support.
Posts: 213
Threads: 62
Joined: May 2018
Reputation:
4
shellies/TRV_ROM1/thermostat/0/command/ext_t
This worked over MQTT. had to dig in the docu, TRV needed to be set as Floor_heating to use external value.
Quick question, can I have several MQTT scripts running, e.g one for each component? Or should I run all in one script?
Posts: 7773
Threads: 42
Joined: Jun 2015
Reputation:
447
You can use multiple scripts but it makes more sense to handle everything in a single script.
Posts: 213
Threads: 62
Joined: May 2018
Reputation:
4
YEah, I guess. just thought it would be easier to auto generate GA's in separate scrips.
|