Adding LUA library to SHAC/NAC

Discussion in 'C-Bus Automation Controllers' started by Damaxx, Apr 4, 2019.

  1. Damaxx

    Damaxx

    Joined:
    May 12, 2008
    Messages:
    228
    Likes Received:
    47
    Was going over some more ideas for scripts and come across this post from Daniel in Jan 2018

    So that go me wondering - The LUA MQTT library is a very simple library with standard dependencies.

    https://github.com/geekscape/mqtt_lua/blob/master/lua/mqtt_library.lua

    Before I go dive into the deep end and brick my controller, are there any known caveats with adding functions?
    If we could get simple MQTT implementation, it would open a trove of possibilities.
     
    Damaxx, Apr 4, 2019
    #1
  2. Damaxx

    Pie Boy

    Joined:
    Nov 21, 2012
    Messages:
    248
    Likes Received:
    31
    Location:
    New Zealand
    Pie Boy, Apr 15, 2019
    #2
  3. Damaxx

    Damaxx

    Joined:
    May 12, 2008
    Messages:
    228
    Likes Received:
    47
    Can you elaborate on how you got MQTT going?
     
    Damaxx, Apr 16, 2019
    #3
  4. Damaxx

    Pie Boy

    Joined:
    Nov 21, 2012
    Messages:
    248
    Likes Received:
    31
    Location:
    New Zealand
    What are you trying to achieve exactly? this will bring in messages from an all ready configured broker on the same network as the SHAC making the SHAC a Mqtt client, i have mqtt talking to cbus both ways like this with a few esp8266 units and such

    The lib is already loaded in the SHAC firmware somewhere so you just need to require it etc, i stumbled on this by accident...
    Create a resident script with 0 delay to connect to the broker and topics see below, the lib is well documented as per link above

    mqtt = require("mosquitto")
    client = mqtt.new()

    client.ON_CONNECT = function()
    log("MQTT connected")
    client:subscribe("Some Topic")
    local mid = client:subscribe(Some Topic", 2)
    end

    client.ON_MESSAGE = function(mid, topic, payload)

    if topic == "Some topic" then

    if payload == "Some Payload" then
    -- Do something
    end

    end

    log(topic, payload)
    end

    broker = 'xxx.xxx.xxx.xxx' -- Broker ip adress
    client:connect(broker)
    client:loop_forever()
     
    Pie Boy, Apr 17, 2019
    #4
    zei20t and Damaxx like this.
  5. Damaxx

    Damaxx

    Joined:
    May 12, 2008
    Messages:
    228
    Likes Received:
    47
    Awesome - that's what I was looking for.
    I was trying different ways of mqtt - all of which required an "mqtt" library.
    Didn't even think to try mosquitto.
    Much appreciated.
     
    Damaxx, Apr 17, 2019
    #5
  6. Damaxx

    garethadams

    Joined:
    Oct 25, 2015
    Messages:
    13
    Likes Received:
    0
    Location:
    Perth
    I have been looking at implementing a MQTT client on my SHAC to my mosquitto broker. Reading this thread I see others have been successful with this integration, I seem to be failing....

    Looking at https://github.com/xHasKx/luamqtt and also https://github.com/geekscape/mqtt_lua/blob/master/lua/mqtt_library.lua documentation, the library used by SHAC does not follow these. I see the library being required is 'mosquitto' but can't find any documentation.

    I have added the following resident script with a 0 delay;

    Code:
    -- load mqtt module
    mqtt = require("mosquitto")
    
    -- create new mqtt client
    client = mqtt.new()
    
    log("created MQTT client", client)
    
    client.ON_CONNECT = function()
      log("MQTT connected")
      client:subscribe("dev/test")
      local mid = client:subscribe("dev/test", 2)
    end
    
    client.ON_MESSAGE = function(mid, topic, payload)
    
        if topic == "dev/test" then
    
          if payload == "hello" then
         
     log(topic, payload)
         
    end
     
    end
    
    log(topic, payload)
    end
    
    broker = '192.168.2.35'
    client:connect(broker)
    client:loop_forever()
    The mosquito broker is working as proven with MQTT-Spy and Putty. I can sub/pub to topic dev/test using these but have had no success with the SHAC. I am getting the following error from the log on mosquitto, 192.168.2.211 is the SHAC.

    1562734124: New connection from 192.168.2.211 on port 1883.
    1562734124: Socket error on client <unknown>, disconnecting.

    Any help on this would be appreciated.
     
    garethadams, Jul 10, 2019
    #6
  7. Damaxx

    Pie Boy

    Joined:
    Nov 21, 2012
    Messages:
    248
    Likes Received:
    31
    Location:
    New Zealand
    Just an idea.
    Do you have any security/ password broker side? Username/ password etc if so, you will need to specify log In as below

    client:login_set("user","password")

    before client:connect (broker)
     
    Pie Boy, Jul 10, 2019
    #7
  8. Damaxx

    garethadams

    Joined:
    Oct 25, 2015
    Messages:
    13
    Likes Received:
    0
    Location:
    Perth
    @Pie Boy , Thank You. It worked. Added the client:logion_set("user","password") to the script and managed to subscribe to a topic to receive the payload message.

    Do you have any documentation on how the library is implemented? I did wonder about the security on the broker side but didn't know how to implement in the SHAC, now I do!
     
    garethadams, Jul 10, 2019
    #8
  9. Damaxx

    Pie Boy

    Joined:
    Nov 21, 2012
    Messages:
    248
    Likes Received:
    31
    Location:
    New Zealand
    Pie Boy, Jul 11, 2019
    #9
  10. Damaxx

    garethadams

    Joined:
    Oct 25, 2015
    Messages:
    13
    Likes Received:
    0
    Location:
    Perth
    That's the one, thanks for your help.
     
    garethadams, Jul 12, 2019
    #10
  11. Damaxx

    garethadams

    Joined:
    Oct 25, 2015
    Messages:
    13
    Likes Received:
    0
    Location:
    Perth
    I am trying to read and write several topics/payloads. Is it better to create a resident script for each one or read all values in the same script?
     
    garethadams, Jul 13, 2019
    #11
  12. Damaxx

    znelbok

    Joined:
    Aug 3, 2004
    Messages:
    1,151
    Likes Received:
    17
    Working on this now as well (SHAC online for two hours now).

    I am able to subscribe and can see the payloads in the log file.

    Conceptually - what is the best practice here. Based on the above question, do we just use a lot of IF statements in the resident script to take action on.

    Also, what about publishing data. I saw the script for pub, but I want to be able to call the script and pas it a value(s) (topic and payload) from other scripts.

    e.g. An event based script where something happens and then I call the pub script with a topic and payload
    if group5 on then mqtt_pub(cmd/Fan/POWER,on)

    just started learning so I may have jumped the gun here with a really basic question.
     
    znelbok, Sep 2, 2020
    #12
  13. Damaxx

    Pie Boy

    Joined:
    Nov 21, 2012
    Messages:
    248
    Likes Received:
    31
    Location:
    New Zealand
    depends how many topic/s you are planing to use, also depends on how many connections you want to your broker etc. i try to have send and receive separate in the shac and have the sending based on event, in my experience resident script can consume many resources if you use lots of if statements and especially if you are asking a Cbus group what its level is every x seconds, it will flood the Cbus network... in all reality you only need to know if the value has changed to update etc

    for sending i open and close the connection I only have a few Ga/s i want to push data to mqtt with (the rest are listening for data from mqtt) the way i do it is by creating a user library and have a send function for mqtt then i just call said function from any event script.

    send_mqtt('some topic', 'some payload')

    Code:
    mqtt = require("mosquitto")
    client = mqtt.new()
    mqtt_username = 'XXXXXX'
    mqtt_password = 'XXXXXX'
    
    function handle_connection()
      broker = "192.168.1.1"
    client:login_set(mqtt_username, mqtt_password)
    client:connect(broker)
    client:loop_forever()
    end
    
    function send_mqtt(topic, payload)
    client.ON_CONNECT = function()
           -- client:publish("world", "hello")
         local qos = 1
        local retain = false
        local mid = client:publish(topic, payload, qos, retain)
    end
    
    client.ON_PUBLISH = function()
        client:disconnect()
    end
     
    handle_connection()
    end
    
    
    if you have many you want to send to mqtt i would do a keyword on each Ga and a single event script (with keyword) with something like

    send_mqtt(event.dst, event.getvalue())

    This would publish the level of the GA to a topic with the same value as event.dst which is a string of the Ga like '0/56/22'

    FYI you can also write keywords with a loop like this, run it once it will insert the keyword into the database so even if the GA dose not exist the keyword will exist if you make the Ga after running the code.

    it would be a smart idea to create a backup before "Experimenting"... i didn't do that on more than one occasion and it was a pain if you get it wrong...

    Code:
    
    for i = 0,255 do
    grp.addtags('0/56/'..i, 'tags')
    end
    
    
     
    Last edited: Sep 2, 2020
    Pie Boy, Sep 2, 2020
    #13
  14. Damaxx

    znelbok

    Joined:
    Aug 3, 2004
    Messages:
    1,151
    Likes Received:
    17
    Thanks.

    All I want to do is when a certain GA is turned on (or set to level) then send a pub command. I currently have GA doing this through CQC but this is a way or short circuiting CQC and having the lighting system do it directly.

    I'll give the function a go and see how it works for me.

    Didn;t work, but a question or two more.

    If I want to only open one connection for pub - I could do this as a resident script and that would be the first part of the function you posted. The User library would be the function itself that has the values passed in.

    Is there anything inherently wrong with opening the one connection?

    Update II - helps to write the correct topic. Fixed that and its working like a charm. Now to work out Event based scripts
     
    Last edited: Sep 2, 2020
    znelbok, Sep 2, 2020
    #14
  15. Damaxx

    KevinH

    Joined:
    Aug 3, 2004
    Messages:
    171
    Likes Received:
    0
    Location:
    Yorkshire. UK
    I saw the news from CQC re open sourcing and your comments.

    I use MQTT extensively in my own system with many controllers/devices and the integration with the SHAC and C-Bus has been brilliant. I tag my groups and measurement sensors and use them to update status on MQTT with one event driven script.

    A single permanent connection to MQTT is advantageous as then you can keep monitoring for any commands coming in from MQTT to update C-Bus devices. Also in most MQTT setups only one client with the same clientID can be connected to the broker. Subsequent connects will be dropped.
     
    KevinH, Sep 8, 2020
    #15
  16. Damaxx

    KevinH

    Joined:
    Aug 3, 2004
    Messages:
    171
    Likes Received:
    0
    Location:
    Yorkshire. UK
    @Pie Boy or anyone

    Sorry to revive an old post but is it possible to create an event based script that keeps the MQTT connection open that I can just call from multiple devices,rather than closing it after each publish? Or do I have perhaps to call another script (not an event script) from within the events script.. Its a good idea to use keywords.

    With all the work the SHAC is doing currently is is connecting and disconnecting (without issue) every second or so to publish payloads but I'd like it to stay connected.
     
    KevinH, May 17, 2021
    #16
  17. Damaxx

    Pie Boy

    Joined:
    Nov 21, 2012
    Messages:
    248
    Likes Received:
    31
    Location:
    New Zealand
    Pie Boy, May 17, 2021
    #17
  18. Damaxx

    pspeirs

    Joined:
    Nov 23, 2013
    Messages:
    185
    Likes Received:
    10
    Location:
    Sydney
    Hi All,
    An old topic I know, but wondering if anyone knows where this is going wrong . . .

    I get the log printout and the first SetObjectByTag value saved, however with the remaining 3 SetObjectByTag statements left in and I get the below error message. Any help would be appreciated.


    User library functions:86: attempt to index field 'data' (a nil value)
    stack traceback:
    User library functions:86: in function 'SetObjectByTag'
    Resident script:37: in function <Resident script:18>
    [C]: in function 'loop_forever'



    Code:
    -- load mqtt module
    mqtt = require("mosquitto")
    local json = require "json"
    
    -- create new mqtt client
    client = mqtt.new("xxxxxxxxxxxxxx")
    
    client.ON_CONNECT = function()
        log("MQTT client connected")
        client:subscribe(topicname)
        local mid = client:subscribe("device/xxxxxxx/realtime", 2)
        log(string.format("Subscribed to %s", topicname))
    end
    
    
    client.ON_MESSAGE = function(mid, topic, payload)
    
        if topic == topicname then
    
            local decode = json.decode(payload)
            local max_idx = table.maxn(decode.Datas)
    
            for idx = 1, max_idx
            do
                local volts = decode.Datas[idx][1]
                local current = decode.Datas[idx][2]
                local power = decode.Datas[idx][3]
                local energy = decode.Datas[idx][4]
               
                log(string.format("Phase: %u, V: %s, A: %s, W: %s, kWh: %s", idx, volts, current, power, energy))
                SetObjectByTag(string.format('iammeter_%u_volts', idx), volts)
                SetObjectByTag(string.format('iammeter_%u_curent', idx), current)
                SetObjectByTag(string.format('iammeter_%u_power', idx), power)
                SetObjectByTag(string.format('iammeter_%u_energy', idx), energy)
               
            end
           
        end
    end
    
    
    
    broker = 'mqtt.iammeter.com'
    client:login_set("xxxxx","xxxxxx")
    topicname = "device/xxxxxxx/realtime"
    
    client:connect(broker)
    client:loop_forever()
     
    pspeirs, Oct 4, 2021
    #18
  19. Damaxx

    Pie Boy

    Joined:
    Nov 21, 2012
    Messages:
    248
    Likes Received:
    31
    Location:
    New Zealand
    i would be lookin here at your library function,
    User library functions:86: attempt to index field 'data' (a nil value)
    the var data in the function has a nil value - according to the error message.

    what are the data types of the var current, power and energy i assume they are string/s?
    what are the data types of these obj you are writing to all user param, string, uint etc?
    do the two match up or do you need some conversion to make the recieved var match with the obj datatype?
     
    Pie Boy, Oct 4, 2021
    #19
  20. Damaxx

    Ashley

    Joined:
    Dec 1, 2005
    Messages:
    1,524
    Likes Received:
    173
    Location:
    Adelaide, Australia
    Show us SetObjectByTag
     
    Ashley, Oct 4, 2021
    #20
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.