This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

Sauna RS485 connection with LM
#1
Hi,
I want to send command for sauna control over RS485
   

Comand list



   




How need to look my command in LM?
Code:
require('serial')
port = serial.open('/dev/RS485-1', { baudrate = 57600, parity = 'none', duplex = 'half', databits = 8, stopbits = 1 })
port:flush()

log = port:write (info)
port:close()
Reply
#2
Code:
port:write('set sauna on\r')
port:write('set sauna val 70\r')
Reply
#3
This is correct that I done in resident  for reading:
Code:
require('serial')
port = serial.open('/dev/RS485-1', { baudrate = 57600, parity = 'none', duplex = 'half', databits = 8, stopbits = 1 })
port:flush()

grp.write('32/2/2', port:write(('get sauna val\r'), 'uint16'))

port:close()

   
Reply
#4
If you want to query status periodically then things get more complicated. You need to have a single resident script which will handle both reading and writing because you cannot have multiple scripts accessing serial port at the same time.

You also need to parse the response because the reply will contain some additional characters.
This should log raw response of temperature value.
Code:
function readack()
  local line = {}

  while true do
    local char, err = port:read(1, 5)

    if char == nil then
      return nil, err
    elseif char == ';' then
      break
    else
      line[ #line + 1 ] = char
    end
  end

  return table.concat(line)
end

port:write('get sauna val\r')
res, err = readack()
log(res, err)
Reply
#5
Ok connection is working maybe you know why I get not correct value?
   
Reply
#6
Evrithing is good its working code:

Code:
require('serial')
port = serial.open('/dev/RS485-1', { baudrate = 57600, parity = 'none', duplex = 'half', databits = 8, stopbits = 1 })
port:flush()


function readack()
 local line = {}

 while true do
   local char, err = port:read(1, 5)

   if char == nil then
     return nil, err
   elseif char == ';' then
     break
   else
     line[ #line + 1 ] = char
   end
 end

 return table.concat(line)
end

port:write('get sauna\r')
res, err = readack()
log(res, err)

port:close()
Reply
#7
Hi.

I get response timeout when running this script in wiser knx. is there any difference for RS-485 port?

I´ve tested this script over here and also with
This:
Code:
require('serial')

local port, errorMsg = serial.open('/dev/RS485', { baudrate = 57600, parity = 'none', duplex = 'half', databits = 8, stopbits = 1 })

-- Kontrollera om porten öppnades framgångsrikt
if not port then
    log("Kunde inte öppna porten: " .. (errorMsg or "Okänt fel"))
    return
end

port:flush()

-- Funktion för att läsa svar från bastun
local function readack()
  local line = {}

  while true do
    local char, err = port:read(1, 5)

    if char == nil then
      return nil, err
    elseif char == ';' then
      break
    else
      table.insert(line, char)
    end
  end

  return table.concat(line)
end

-- Kontrollera om bastun ska vara PÅ eller AV
local bastuState = grp.getvalue('37/1/1')
if bastuState then
    port:write('set sauna on\r')
else
    port:write('set sauna off\r')
end

-- Ställ in bastutemperaturen baserat på KNX-gruppadressen, värde mellan 30-110 grader
local temperature = grp.getvalue('37/1/3')
port:write('set sauna val ' .. temperature .. '\r')

-- Läs tillbaka värdet från bastun
port:write('get sauna val\r')

local res, err = readack()

if res then
    log("Sauna värde: " .. res)
    grp.checkwrite('37/1/0', res)  -- Skriver bastustatus till angiven adress
    grp.checkwrite('37/1/4', res)  -- Skriver tillbaka temperaturstatus till den nya gruppadressen
else
    log("Fel vid läsning av bastu värde: " .. (err or "Okänt fel"))
end

-- Stäng porten
port:close()
Anone who can see something wrong in this script?
Reply
#8
Script should call readack() after every command (both set and get). But this won't cause last readack() to return timeout. Something is wrong on the communication level. Try swapping A/B and see if GND is connected.
Reply
#9
(06.10.2023, 12:43)admin Wrote: Script should call readack() after every command (both set and get). But this won't cause last readack() to return timeout. Something is wrong on the communication level. Try swapping A/B and see if GND is connected.

Thanks this helped.

Now runs thhis script and its working.
Code:
require('serial')

local port, errorMsg = serial.open('/dev/RS485', { baudrate = 57600, parity = 'none', duplex = 'half', databits = 8, stopbits = 1 })

if not port then
    log("Kunde inte öppna porten: " .. (errorMsg or "Okänt fel"))
    return
end

port:flush()

-- Funktion för att läsa svar från bastun
local function readack()
  local line = {}
  local crlf_received = false

  while not crlf_received do
    local char, err = port:read(1, 5)

    if char == nil then
      return nil, err
    elseif char == '\r' then
      -- Ignorerar CR och väntar på LF
    elseif char == '\n' then
      crlf_received = true
    else
      table.insert(line, char)
    end
  end

  local response = table.concat(line)
  if string.sub(response, -1) == ';' then
    response = string.sub(response, 1, -2)  -- Ta bort semikolon i slutet
  end
  return response
end

-- Loggar och skickar kommandon till bastustyrningen, läser sedan svaret
local function sendAndRead(command)
    log("Skickat kommando: " .. command)
    port:write(command .. '\r\n')
    return readack()
end

-- Kontrollera om bastun ska vara PÅ eller AV och läs svar
local bastuState = grp.getvalue('37/1/1')
sendAndRead(bastuState and 'set sauna on' or 'set sauna off')

-- Ställ in bastutemperaturen baserat på KNX-gruppadressen och läs svar
local temperature = grp.getvalue('37/1/3')
local tempResponse = sendAndRead('set sauna val ' .. temperature)
if tempResponse then
    log("Svar på temperaturinställning: " .. tempResponse)
    -- Uppdatera KNX-gruppadressen med det utlästa värdet
    grp.checkwrite('37/1/4', temperature)
end

-- Läs bastuns nuvarande status
local currentStatus = sendAndRead('get sauna')
if currentStatus then
    local status = string.match(currentStatus, "SAUNA%s(%w+)")
    if status then
        log("Bastuns nuvarande status: " .. status)
        local knxStatus = (status == "on") and 1 or 0
        grp.checkwrite('37/1/0', knxStatus)
    else
        log("Kunde inte tolka bastuns nuvarande status från svaret: " .. currentStatus)
    end
end

-- Stäng porten
port:close()


Build on more functions for the sauna with following script and with the new one it does not work, is there any solution you can see?
Code:
require('serial')

local port, errorMsg = serial.open('/dev/RS485', { baudrate = 57600, parity = 'none', duplex = 'half', databits = 8, stopbits = 1 })

if not port then
    log("Kunde inte öppna porten: " .. (errorMsg or "Okänt fel"))
    return
end

port:flush()

-- Funktion för att läsa svar från bastun
local function readack()
  local line = {}
  local crlf_received = false

  while not crlf_received do
    local char, err = port:read(1, 5)

    if char == nil and err then
      log("Läsfel: " .. err)
      return nil, err
    elseif char == '\r' or char == '\n' then
      -- Hanterar CR, LF och potentiellt icke-skrivbara tecken
      if char == '\n' then
        crlf_received = true
      end
    elseif char then
      table.insert(line, char)
    end
  end

  local response = table.concat(line)
  log("Mottaget svar: " .. response)
  if string.sub(response, -1) == ';' then
    response = string.sub(response, 1, -2)
  end
  return response
end


-- Loggar och skickar kommandon till bastustyrningen, läser sedan svaret
local function sendAndRead(command)
    log("Skickat kommando: " .. command)
    port:write(command .. '\r\n')
    return readack()
end

-- Hantera Timer-status (starta/stoppa)
local function handleTimerStatus()
    local timerStatus = grp.getvalue('37/1/5')
    local response = sendAndRead(timerStatus and 'set timer on' or 'set timer off')
    if response then
        local status = string.match(response, "timer%s(%w+);")
        grp.checkwrite('37/1/6', status == "on" and 1 or 0)
    end
end

-- Sätta tid för Timer och hämta dess status
local function setAndQueryTimerTime()
    local timerTime = grp.getvalue('37/1/7')
    sendAndRead('set timer val ' .. timerTime)

    local timerTimeResponse = sendAndRead('get timer val')
    if timerTimeResponse then
        local timeValue = string.match(timerTimeResponse, "timer%s(%d+);")
        grp.checkwrite('37/1/8', tonumber(timeValue))
    end
end

-- Hantera Userprogram
local function handleUserProgram()
    local userProgram = grp.getvalue('37/1/9')
    local response = sendAndRead(userProgram and 'set user-prog on' or 'set user-prog off')
    if response then
        local status = string.match(response, "user%-prog%s(%w+);")
        grp.checkwrite('37/1/10', status == "on" and 1 or 0)
    end

    local programNumber = grp.getvalue('37/1/11')
    local programResponse = sendAndRead('set user-prog val ' .. programNumber)
    if programResponse then
        local currentProgram = string.match(programResponse, "user%-prog%s(%d+);")
        grp.checkwrite('37/1/12', tonumber(currentProgram))
    end
end

-- Hämta bastu Control Unit Status
local function getControlUnitStatus()
    local response = sendAndRead('get status')
    if response then
        -- Matcha statusen efter "STATUS " utan att kräva ett semikolon i slutet
        local status = string.match(response, "STATUS%s(%w+)")
        if status then
            -- Skickar statussvaret som en textsträng till KNX-gruppadressen
            grp.checkwrite('37/1/20', "Bastu " .. status)
        else
            log("Kunde inte tolka Control Unit status från svaret: " .. response)
        end
    end
end

-- Anropa funktionerna
handleTimerStatus()
setAndQueryTimerTime()
handleUserProgram()
getControlUnitStatus()

-- Stäng porten
port:close()
Reply
#10
Do you get anything in logs? Any response from the readack() function?
Reply
#11
Gets this in my log, sorry for the swedish text in log Smile

Bastu Status REV 13.12.2023 09:25:16
* string: Skickat kommando: set timer val 240
Bastu Status REV 13.12.2023 09:25:16
* string: Mottaget svar: TIMER 240min ;
Bastu Status REV 13.12.2023 09:25:16
* string: Skickat kommando: get timer val
Bastu Status REV 13.12.2023 09:25:16
* string: Mottaget svar: TIMER 240min ;
Bastu Status REV 13.12.2023 09:25:16
* string: Skickat kommando: set user-prog val 1
Bastu Status REV 13.12.2023 09:25:16
* string: Mottaget svar: USER-PROG 1 ;
Bastu Status REV 13.12.2023 09:25:16
* string: Skickat kommando: get status
Bastu Status REV 13.12.2023 09:25:16
* string: Mottaget svar: STATUS OK;

The sauna activates with one relay but directly shuts off.
Reply
#12
The response is uppercase so your regexp won't work because it's lowercase. Use 'USER%-PROG%s+(%d+)' for user program detection and 'TIMER%s+(%w+)' for timer. Modify other regexps in a similar way.
Reply
#13
Okey, now gets this in Log.

Bastu Status REV 13.12.2023 09:52:22
* string: Skickat kommando: set timer val 240
Bastu Status REV 13.12.2023 09:52:22
* string: Mottaget svar: TIMER 240min ;
Bastu Status REV 13.12.2023 09:52:22
* string: Skickat kommando: get timer val
Bastu Status REV 13.12.2023 09:52:22
* string: Mottaget svar: �TIMER 240min ;
Bastu Status REV 13.12.2023 09:52:22
* string: Skickat kommando: set user-prog off
Bastu Status REV 13.12.2023 09:52:22
* string: Mottaget svar: USER-PROG off;
Bastu Status REV 13.12.2023 09:52:22
* string: Skickat kommando: set user-prog val 1
Bastu Status REV 13.12.2023 09:52:22
* string: Mottaget svar: USER-PROG 1 ;
Bastu Status REV 13.12.2023 09:52:22
* string: Skickat kommando: get status
Bastu Status REV 13.12.2023 09:52:22
* string: Mottaget svar: STATUS OK;
Reply
#14
Post you current script. What exactly is not working after the regexp changes?
Reply


Forum Jump: