Programming Conundrum  [Solved]

Easy to use, 100% Lua-based event scripting framework.

Moderator: leecollings

Post Reply
gregoinc
Posts: 18
Joined: Sunday 08 November 2020 8:29
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Programming Conundrum

Post by gregoinc »

Greetings... new to this forum, and new to Domoticz.

Previously I have been using exclusively ESPEasy, supported by NodeRed, Grafana, and Blynk. I am beginning my journey towards a Raspberry Pi based system and have chosen Domoticz as my 'Home Automation' platform. But to be honest, my needs are relative modest, so saying home automation platform is really overkill.

So... my conundrum... how to migrate from the ESPEasy 'rules' based programming to Domoticz dzVents or LUA? I must confess I am no programmer, but have managed to muddle my way through the ESPEasy rules setup. So I am here looking for some tips, hints, and ideas for essentially consolidating the 2 x ESPEasy platforms to a single Raspberry Pi running Domoticz.

Here's my setup...

I have a small room that contains a rack of computer servers etc (yes I work in ICT) and on cooler days sucking air from the outside keeps the room cool. And on hot days I close a damper and the first ESPEasy turns on the air conditioner in the room via an infrared LED.

ESPEasy unit 1 - has 2 x 1 wire temperature sensors and a Infrared LED transmitter connected to a ESP 8266 NodeMCU. Temp sensor 1 monitors the inside temp and Temp sensor 2 monitors the outside.

ESPEasy unit 2 - has 2 relays connected to the ESP 8266 NodeMCU. Relay 1 opens and closes a damper to the outside world, and relay 2 turns a fan on and off.

Here's the ESPEasy Rules code...

ESPEasy1

Code: Select all

On System#Boot do
   notify 1, "%sysname% is started"      // Send email
   timerset,1,30
   heatpumpir,daikin,0,3,0,23,4,2        // Send StopHP IR code on Start
   TaskValueSet 4,1,0                    // Set Heat Pump status to 0
   TaskValueSet 4,2,[Temp1#Temperature]  // Set initial inside temperature
   TaskValueSet 4,3,[Temp2#Temperature]  // Set initial outside temperature
   timerset,4,15                         // Set Timer 4 to 15 seconds
endon

On Rules#Timer=1 do
   timerset,1,30
   TaskValueSet 4,2,[Temp1#Temperature]  // Update inside temp
   TaskValueSet 4,3,[Temp2#Temperature]  // Update outside temp
   if [counter#InTemp] >= 25
    Event,StartHP
   endif
   if [counter#InTemp] <= 23 and [counter#OutTemp] < 19
    Event,StopHP
   endif 
endon

On PIR#switch=1 do 
lcdcmd,on
timerset,2,15
Endon

On StartHP Do
If [counter#status]=0
 heatpumpir,daikin,1,3,0,23,4,2
 TaskValueSet 4,1,1
EndIf
EndOn

On StopHP Do
If [counter#status]=1
 heatpumpir,daikin,0,3,0,23,4,2
 TaskValueSet 4,1,0
EndIf
EndOn

On Clock#Time=All,3:25 do 
  timerSet,3,55
Endon

on Rules#Timer=3 do
  WifiDisconnect
  Reboot
endon

on Rules#timer=4 do
  Publish %sysname%/IP,%ip%
  Publish %sysname%/Temp1/Temp,[counter#InTemp]
  Publish %sysname%/Temp1/Humidity,[Temp1#Humidity]
  Publish %sysname%/Temp2/Temp,[counter#OutTemp]
  Publish %sysname%/Temp2/Humidity,[Temp2#Humidity]
  Publish %sysname%/AirCon/Status,[counter#status]
  timerSet,4,15
endon
ESPEasy2

Code: Select all

On System#Boot do
   notify 1, "%sysname% is started"      // Send email   
   timerset,1,30       // Set timer 1 to 30 seconds
   timerset,2,30       // Set timer 2 to 30 seconds
   timerset,4,30       // Set timer 4 to 30 seconds
   gpio,12,1           // Turn off the fan
   gpio,14,1           // Close the damper
   TaskValueSet 7,1,0  // Set Damper to Close
   TaskValueSet 7,2,0  // Set Fan to Off
   Let,1,22            // Set lower temp to 22
   Let,2,24            // Set upper temp to 24
endon

On Rules#Timer=1 do
   timerset,1,30
   if [Temp1#Temperature] >= [var#2] and [status#Damper]=1
     Event,StartFan
   endif   
   if [Temp1#Temperature] <= [var#1] or [status#Damper]=0
     Event,StopFan 
   endif 
endon

On Rules#Timer=2 do
   timerset,2,30
   if [Temp2#Temperature] < 19 and [counter#Dummy]=0
    Event,OpenDamper
   endif
   if [Temp1#Temperature] >= 25
    Event,CloseDamper
   endif 
endon

On OpenDamper Do
If [status#Damper]=0
 gpio,14,0    // Open the damper
 TaskValueSet 7,1,1
EndIf
EndOn

On CloseDamper Do
If [status#Damper]=1
 gpio,14,1    // Close the damper
 TaskValueSet 7,1,0
EndIf
EndOn

On StartFan Do
If [status#Fan]=0
 gpio,12,0    // Turn on the fan
 TaskValueSet 7,2,1
EndIf
EndOn

On StopFan Do
If [status#Fan]=1
 gpio,12,1    // Turn off the fan
 TaskValueSet 7,2,0
EndIf
EndOn

On ACStatusOn
Let,3,1
EndOn

On Clock#Time=All,3:26 do 
  timerSet,3,55
Endon

on Rules#Timer=3 do
  WifiDisconnect
  Reboot
endon

on Rules#timer=4 do
  Publish %sysname%/IP,%ip%
  Publish %sysname%/Damper/Status,[status#Damper]
  Publish %sysname%/Fan/Status,[status#Fan]
  Publish %sysname%/Door/Status,[StudioDoor#State]
  timerSet,4,30
endon
As you can probably see from above... this is not rocket science, and it can probably be improved or updated to control things much better. In essence, it's a temperature controller... which keeps the room cool, either by fresh air or air-conditioning.

Ok, that's it. Any help guidance greatly appreciated. If I've not been clear enough with my description then please ask me more questions.

I really hope someone on here has a similar setup, and can provide examples on the dzVents or LUA setup they used?

Thanks, Mark
gregoinc
Posts: 18
Joined: Sunday 08 November 2020 8:29
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Programming Conundrum

Post by gregoinc »

No responses to above... so I've identified some code to start with here viewtopic.php?t=26335 which received input and support by waaren.

I will try and learn as I go... I am going to start by trying to duplicate the code for ESPEasy 2 first... that being to open and close the damper and turn on the fan.

I understand where to define the names of my temperature sensors Inside Temp and Outside Temp and the Damper and Fan, but I am not sure where to place the names inside the lower portions of the code?

Also, a question for the timer... rather than running every minute, can you run say every 30 seconds?

Code: Select all

-- Temp control
return {
             on =   {  
                        timer         =   { "every minute" },
                    },
                      
        logging =   {   
                        level         =   domoticz.LOG_ERROR,                   
                        marker        =   "Temp control"
                    },
                        
           data =   {   
                        lowTemperature  = { initial = true },
                    },
     
    execute = function(dz)

        local temperature           = dz.devices("Inside Temp").temperature
        local temperature           = dz.devices("Outside Temp").temperature
        local switch                = dz.devices("Damper")
        local switch                = dz.devices("Fan")
        local switchIsOff           = switch.state == "Off"
        local lowerTemperature      = 20
        local higherTemperature     = 25
        local comingFromLow         = dz.data.lowTemperature
        local temperatureInRange    = temperature > lowerTemperature and temperature < higherTemperature
        
        
        dz.data.lowTemperature = temperature < lowerTemperature                   -- remember coming from low 
        
        if switchIsOff and temperatureInRange and comingFromLow then              -- between 20-40 and coming from < 20 ==>> switchOn
           switch.switchOn()
        elseif not temperatureInRange and not switchIsOff then                    -- > 40 or < 20 switchOff
            switch.switchOff()
            if temperature > higherTemperature then                               -- No longer coming from low 
                dz.data.lowTemperature = false
            end    
        end    
    end
}                           
Hope I can get some input/ideas/advice... apology for being an annoying noob.
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Programming Conundrum

Post by waaren »

gregoinc wrote: Tuesday 10 November 2020 3:55 Hope I can get some input/ideas/advice...
See my comments / modifications in your script

Code: Select all

-- Temp control

local scriptVar = 'tempControl'

return
{
    on =
    {
        timer =
        {
            'every minute',   -- domoticz events based on timers are triggered once a minute max.
        },
        customEvents = -- used to increase frequency to once every 30 seconds.
        {
            scriptVar,
        }
    },

        logging =   {
                        level         =   domoticz.LOG_DEBUG, -- If set to domoticz.LOG_ERROR you will only see something if dzVents encountered an error
                                                               -- So best to start with domoticz.LOG_DEBUG until your script works as expected.
                        marker        =   scriptVar,
                    },

           data =   {
                        lowTemperature  = { initial = true },
                    },

    execute = function(dz, item)

        if item.isTimer then
            dz.emitEvent(scriptVar).afterSec(30) -- this wil trigger the customEvent in the On section and therewith increase the frequency to every 30 seconds
        end

-- commented this block an corrected it below
--[[        local temperature           = dz.devices('Inside Temp').temperature
        local temperature           = dz.devices('Outside Temp').temperature  -- this second use of 'temperature' as varname does overwrite the previous one.
        local switch                = dz.devices('Damper')
        local switch                = dz.devices('Fan') -- this second use of 'switch' as varname does overwrite the previous one.
        local switchIsOff           = switch.state == 'Off' -- which one ?
        local lowerTemperature      = 20
        local higherTemperature     = 25
        local comingFromLow         = dz.data.lowTemperature
        local temperatureInRange    = temperature > lowerTemperature and temperature < higherTemperature -- which of the 2?
]]
        local insideTemperature = dz.devices('Inside Temp').temperature
        local outsideTemperature = dz.devices('Outside Temp').temperature
        local damper = dz.devices('Damper')
        local fan = dz.devices('Fan') -- this second use of 'switch' as varname does overwrite the previous one.

        local fanIsOff = fan.state == 'Off'
        local damperIsOff = damper.state == 'Off'

        local lowerTemperature = 20
        local higherTemperature = 25
        local comingFromLow = dz.data.lowTemperature
        local temperatureInRange = insideTemperature > lowerTemperature and insideTemperature< higherTemperature


        -- assumed you want insideTemperature and fan but cannot be sure
        dz.data.lowTemperature = insidetemperature < lowerTemperature                   -- remember coming from low

        if fanIsOff and temperatureInRange and comingFromLow then              -- between 20-40 and coming from < 20 ==>> switchOn
           fan.switchOn()
        elseif not temperatureInRange and not fanIsOff then                    -- > 40 or < 20 switchOff
            fan.switchOff()
            if insidetemperature > higherTemperature then                               -- No longer coming from low
                dz.data.lowTemperature = false
            end
        end
    end
}                           
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
gregoinc
Posts: 18
Joined: Sunday 08 November 2020 8:29
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Programming Conundrum

Post by gregoinc »

Greetings from Australia to you waaren... and my gratitude to you for your help. I will attempt to outline my comments below.

As I am learning the syntax I completely understand the approach you've taken... thank you for that.

Code: Select all

        local insideTemperature = dz.devices('Inside Temp').temperature
        local outsideTemperature = dz.devices('Outside Temp').temperature
Regarding the comment below... are you saying the use of the 'switch' varname for Fan would still be an issue?

Code: Select all

        local damper = dz.devices('Damper')
        local fan = dz.devices('Fan') -- this second use of 'switch' as varname does overwrite the previous one.
The damper is an interesting unit... when the relay is 'off' the damper is closed, and when the relay is 'on' the damper is open.

Code: Select all

        local fanIsOff = fan.state == 'Off'
        local damperIsOff = damper.state == 'Off'
The logic currently works like this... the Fan should never turn on unless the damper is open, allowing cool air from the outside to come into the room. The damper only opens when the outside temperature is below 19 degrees Celsius. Once the outside temperature hits 25 degrees Celsius the damper closes and due to the damper being closed the fan stops (see pseudo code below). Not saying this is the right way to do this... just my amateur approach.

Written in pseudo code...

if (Inside Temp is >= 24 and the damper is open then start the fan) endif
if (Inside Temp is <= 22 or the damper is closed then stop the fan) endif
if (Outside Temp is < 19 then open the damper) endif
if (Inside Temp >= 25 then close the damper) endif

Future enhancement... (requires an Infrared LED)
If (Outside Temp >= 25 and Inside Temp > 24 then start the air conditioner) endif

Note: with using two NodeMCU's, one of them controls the air conditioner independently of the second NodeMCU that controls the damper and fan.

The logic above could probably do with a lot of improvement, because there are situations where the fan and air conditioner are running at the same time... so it probably needs a major rethink... by someone more qualified than me :(

Code: Select all

        local lowerTemperature = 20
        local higherTemperature = 25
        local comingFromLow = dz.data.lowTemperature
        local temperatureInRange = insideTemperature > lowerTemperature and insideTemperature< higherTemperature
This part probably needs some work... and here in lies the conundrum... the code needs to open/close the damper based upon temperature conditions outside, and run the fan when the outside temperature is lower than the inside i.e. free cooling. Would be really awesome if I could build in some type of Hysteresis... but maybe that's a pipe dream :)

Code: Select all

        -- assumed you want insideTemperature and fan but cannot be sure
        dz.data.lowTemperature = insidetemperature < lowerTemperature                   -- remember coming from low

        if fanIsOff and temperatureInRange and comingFromLow then              -- between 20-40 and coming from < 20 ==>> switchOn
           fan.switchOn()
        elseif not temperatureInRange and not fanIsOff then                    -- > 40 or < 20 switchOff
            fan.switchOff()
            if insidetemperature > higherTemperature then                               -- No longer coming from low
                dz.data.lowTemperature = false
            end
        end
    end
}                           
Eventually I will look to hooking up an infrared LED to send the start/stop codes for the air conditioner.... but can be a later enhancement.

Thanks again for the help waaren... very much appreciated. I have a good friend who lives in Alkmaar, and we visited him last year :)
gregoinc
Posts: 18
Joined: Sunday 08 November 2020 8:29
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Programming Conundrum

Post by gregoinc »

I made a few modifications, however in the log I am seeing the following?

Code: Select all

2020-11-14 14:34:30.445 Status: dzVents: Info: Handling Domoticz custom event for: "tempControl"
2020-11-14 14:34:30.445 Status: dzVents: Info: tempControl: ------ Start internal script: Temp Control: Custom event: "tempControl"
2020-11-14 14:34:30.468 Status: dzVents: Debug: tempControl: Processing device-adapter for Inside Temp: Temperature device adapter
2020-11-14 14:34:30.469 Status: dzVents: Debug: tempControl: Processing device-adapter for Outside Temp: Temperature device adapter
2020-11-14 14:34:30.470 Status: dzVents: Debug: tempControl: Processing device-adapter for Damper: Switch device adapter
2020-11-14 14:34:30.471 Status: dzVents: Debug: tempControl: Processing device-adapter for Fan: Switch device adapter
2020-11-14 14:34:30.472 Status: dzVents: Info: tempControl: ------ Finished Temp Control
2020-11-14 14:34:30.471 Error: dzVents: Error: (3.0.2) tempControl: An error occurred when calling event handler Temp Control
2020-11-14 14:34:30.472 Error: dzVents: Error: (3.0.2) tempControl: ...oticz/scripts/dzVents/generated_scripts/Temp Control.lua:61: attempt to compare nil with number
Here's the code on line 61...

Code: Select all

dz.data.lowTemperature = insidetemperature < lowerTemperature                   -- remember coming from low
Not sure what is causing the issue?

Here's the entire code...

Code: Select all

-- Temp control

local scriptVar = 'tempControl'

return
{
    on =
    {
        timer =
        {
            'every minute',   -- domoticz events based on timers are triggered once a minute max.
        },
        customEvents = -- used to increase frequency to once every 30 seconds.
        {
            scriptVar,
        }
    },

        logging =   {
                        level         =   domoticz.LOG_DEBUG, -- If set to domoticz.LOG_ERROR you will only see something if dzVents encountered an error
                                                               -- So best to start with domoticz.LOG_DEBUG until your script works as expected.
                        marker        =   scriptVar,
                    },

           data =   {
                        lowTemperature  = { initial = true },
                    },

    execute = function(dz, item)

        if item.isTimer then
            dz.emitEvent(scriptVar).afterSec(30) -- this will trigger the customEvent in the On section and therewith increase the frequency to every 30 seconds
        end

-- commented this block an corrected it below
--[[        local temperature           = dz.devices('Inside Temp').temperature
        local temperature           = dz.devices('Outside Temp').temperature  -- this second use of 'temperature' as varname does overwrite the previous one.
        local switch                = dz.devices('Damper')
        local switch                = dz.devices('Fan') -- this second use of 'switch' as varname does overwrite the previous one.
        local switchIsOff           = switch.state == 'Off' -- which one ?
        local lowerTemperature      = 20
        local higherTemperature     = 25
        local comingFromLow         = dz.data.lowTemperature
        local temperatureInRange    = temperature > lowerTemperature and temperature < higherTemperature -- which of the 2?
]]
        local insideTemperature = dz.devices('Inside Temp').temperature
        local outsideTemperature = dz.devices('Outside Temp').temperature
        local damper = dz.devices('Damper')
        local fan = dz.devices('Fan') -- this second use of 'switch' as varname does overwrite the previous one.

        local fanIsOff = fan.state == 'Off'
        local damperIsOff = damper.state == 'Off'
       
        local lowerTemperature = 20
        local higherTemperature = 24
        local comingFromLow = dz.data.lowTemperature
        local temperatureInRange = insideTemperature > lowerTemperature and insideTemperature < higherTemperature


        -- assumed you want insideTemperature and fan but cannot be sure
        dz.data.lowTemperature = insidetemperature < lowerTemperature                   -- remember coming from low

        if fanIsOff and temperatureInRange and comingFromLow then              -- between 20-24 and coming from < 20 ==>> switchOn
           fan.switchOn()
        elseif not temperatureInRange and not fanIsOff then                    -- > 24 or < 20 switchOff
            fan.switchOff()
            if insidetemperature > higherTemperature then                               -- No longer coming from low
                dz.data.lowTemperature = false
            end
        end
    end
}                           
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Programming Conundrum

Post by waaren »

gregoinc wrote: Saturday 14 November 2020 4:36 I made a few modifications, however in the log I am seeing the following?
Case matters !

line 46

Code: Select all

        local insideTemperature = dz.devices('Inside Temp').temperature
line 61

Code: Select all

        dz.data.lowTemperature = insidetemperature < lowerTemperature                   -- remember coming from low
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
gregoinc
Posts: 18
Joined: Sunday 08 November 2020 8:29
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Programming Conundrum

Post by gregoinc »

waaren wrote: Saturday 14 November 2020 6:43 Case matters !
:oops: Sorry...
gregoinc
Posts: 18
Joined: Sunday 08 November 2020 8:29
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Programming Conundrum

Post by gregoinc »

I noticed in my log there is this line occurring regularly...

Code: Select all

2020-11-14 21:41:21.234 (1 Wire Temp) Temp (Outside Temp)
I take above to mean the system is polling the 1 wire temperature sensor call 'Outside Temp' which I am assuming is fine.

I also have a 1 wire temperature sensor connected in serial called 'Inside Temp' i.e. on the same wire as Outside Temp. I dont understand why the Inside Temp is not showing up in the logs?

My dzvents file also doesn't appear to be working, so could that be because the Inside Temp sensor is not being seen/used?

Here's a screen grab on the temperature sensors...
Screenshot from 2020-11-14 21-46-04.jpg
Screenshot from 2020-11-14 21-46-04.jpg (90.36 KiB) Viewed 813 times
Is there a way to watch the execution of the dzvents script in detail, so I can be sure it is work?
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Programming Conundrum

Post by waaren »

gregoinc wrote: Saturday 14 November 2020 11:53 I take above to mean the system is polling the 1 wire temperature sensor call 'Outside Temp' which I am assuming is fine.
System is not polling but the sensor sends this information every xx seconds. According to the last update information of the sensor as shown at the GUI, it does update.
Is there a way to watch the execution of the dzvents script in detail, so I can be sure it is work?
The script has already logging at debug level enabled. If it does not provide enough information yet, you can add some debug log statements in the code like

Code: Select all

dz.log('Measured inside temperature is ' .. insideTemperature, dz.LOG_DEBUG )
and/or enable full debug mode for dzVents in [system], [settings] [other]
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
gregoinc
Posts: 18
Joined: Sunday 08 November 2020 8:29
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Programming Conundrum  [Solved]

Post by gregoinc »

Hi waaren... thank you again. I plan to re-write the if then else area of the code, and will sew where I land after that. Starting to get up to speed on the dzVents syntax and structure.
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest