Page 1 of 1

Bargraph text-device

Posted: Tuesday 21 May 2024 19:53
by RonkA
I made a dZvents script to display values, its not wat is requested in https://www.domoticz.com/forum/viewtopic.php?t=40765 but wanted show it anyway..

The bargraph is fully customable in length and colorzones by adjusting some values.
To work this script a textdevice has to be created and a source for the value to be displayed.

Right now in the current script i take the value from a temperature device to see how warm the water in my solar-storage tank is.
bar_green.PNG
bar_green.PNG (10.42 KiB) Viewed 2019 times
bar_yellow.PNG
bar_yellow.PNG (10.54 KiB) Viewed 2019 times
bar_red.PNG
bar_red.PNG (10.39 KiB) Viewed 2019 times

Code: Select all

-- Bargraph maker for text device -- RonkA
return {
    on = {
        timer = { 'every minute' },
    },
    logging = {
        level = domoticz.LOG_ERROR,
        marker = 'Bargraph',
    },
    execute = function(domoticz, triggeredItem)

        local bar_length = 30        -- number of segments in bargraph; resize as you wish
        local initial_value = 24     -- initial value to start bargraph at
        local max_value = 75         -- max value of Bargraph
        local bar_length_medium = 50 -- 1st color value yellow
        local bar_length_hot = 60    -- 2nd color value red
        
        local text_device = domoticz.devices('Bargraph')  -- idx 335 --> the right idx HAS to be set in line 76 !!!
        local value_device = domoticz.devices('Boiler gemiddelde temperatuur')  -- this device produces the barvalue
        
        local raw_value = value_device.temperature   -- because value_device comes from a temperature device I use .temperature
        local round_value = domoticz.utils.round(raw_value,0)   -- rounding the raw_value to whole numbers
        
        local one_segment = (max_value - initial_value) / bar_length                        -- calculate value of 1 segment
        local green_zone = math.floor((bar_length_medium - initial_value) / one_segment)    -- calculate the number of segments in the green zone
        local yellow_zone = math.floor((bar_length_hot - initial_value) / one_segment)      -- calculate the number of segments in the yellow zone            
        local red_zone = bar_length                                                         -- the remaining segments are for the red zone      
        
        local segment_count = math.floor((raw_value - initial_value) / one_segment)         -- number of segments to display in bargraph 
  

            -- calculate the percentage value round to the nearest whole number
        local percentage = (raw_value - initial_value) / (max_value - initial_value) * 100
        if percentage < 0 then
            percentage = 0
        elseif percentage > 100 then
            percentage = 100
        end
        local percentage_display = math.floor(percentage + 0.5)


            -- building the separate bar segments
        local green_bar = ''
        local yellow_bar = ''
        local red_bar = ''
        
        if segment_count <= green_zone then
            green_bar = '<span style="color: Green;">' .. string.rep('█', segment_count) .. '</span>' ..
                        '<span style="color: Wheat; background-color: Green;">' .. string.rep('▓', green_zone - segment_count) .. '</span>'
            yellow_bar = '<span style="color: Wheat; background-color: yellow;">' .. string.rep('▓', yellow_zone - green_zone) .. '</span>'
            red_bar = '<span style="color: Wheat; background-color: red;">' .. string.rep('▓', red_zone - yellow_zone) .. '</span>'
        elseif segment_count > green_zone and segment_count <= yellow_zone then
            green_bar = '<span style="color: Green;">' .. string.rep('█', green_zone) .. '</span>'
            yellow_bar = '<span style="color: Yellow;">' .. string.rep('█', segment_count - green_zone) .. '</span>' ..
                         '<span style="color: Wheat; background-color: yellow;">' .. string.rep('▓', yellow_zone - segment_count) .. '</span>'
            red_bar = '<span style="color: Wheat; background-color: red;">' .. string.rep('▓', red_zone - yellow_zone) .. '</span>'            
        elseif segment_count > yellow_zone then
            green_bar = '<span style="color: Green;">' .. string.rep('█', green_zone) .. '</span>'
            yellow_bar = '<span style="color: Yellow;">' .. string.rep('█', yellow_zone - green_zone) .. '</span>'
            red_bar = '<span style="color: Red;">' .. string.rep('█', segment_count - yellow_zone) .. '</span>' ..
                      '<span style="color: Wheat; background-color: red;">' .. string.rep('▓', red_zone - segment_count) .. '</span>'
        end    
        
            -- building the bar
        local bar = '<span style="font-family: Consolas; font-weight: bold; font-size: 14px;">' ..
                    initial_value .. '°C' .. '▐' .. green_bar .. yellow_bar .. red_bar .. '▌' .. max_value .. '°C\n' .. 
                    string.rep(' ', segment_count + 4) ..  '▲\n' .. 
                    string.rep(' ', segment_count) .. round_value .. '°C⁞'.. percentage_display .. '%' .. '</span>' 

            -- check if the current message is same as the new message        
        local current_message = text_device.text
        if (current_message ~= bar) then 
            text_device.updateText(bar)  -- Update the text device
            
 ----------> automatically clear the log of the textdevice; change the ip and portnumber accordingly to your setup..
            domoticz.openURL('http://127.17.0.2:80/json.htm?type=command&param=clearlightlog&idx=335')     
        else
            return -- This will stop the script and no log entry will be made
        end         
    end
}
For me this works fine, i hope for others also..
Enjoy!!

Re: Bargraph text-device

Posted: Wednesday 22 May 2024 7:43
by psubiaco
Wow! That's a nice workaround to the missing bargraph in Domoticz!

Re: Bargraph text-device

Posted: Wednesday 22 May 2024 8:46
by lost
Clever hack of the text device!
Did not even noticed html could be used in such device for now, this brings a wide range of specific display customizations.

Re: Bargraph text-device

Posted: Saturday 25 May 2024 14:05
by rron
I like this very much but I want to use it for my power ¨slimme meter". I have adapt some some settings but I think this is not the right way. Can you look at myj adaptions?
Spoiler: show
-- Bargraph maker for text device -- RonkA
return {
on = {
timer = { 'every minute' },
},
logging = {
level = domoticz.LOG_ERROR,
marker = 'Bargraph',
},
execute = function(domoticz, triggeredItem)

local bar_length = 30 -- number of segments in bargraph; resize as you wish
local initial_value = -3000 -- initial value to start bargraph at
local max_value = 3000 -- max value of Bargraph
local bar_length_medium = 50 -- 1st color value yellow
local bar_length_hot = 60 -- 2nd color value red

local text_device = domoticz.devices('Bargraph') -- idx 689 --> the right idx HAS to be set in line 76 !!!
local value_device = domoticz.devices('Slimme meter') -- this device produces the barvalue

local raw_value = value_device.temperature -- because value_device comes from a temperature device I use .temperature
local round_value = domoticz.utils.round(raw_value,0) -- rounding the raw_value to whole numbers

local one_segment = (max_value - initial_value) / bar_length -- calculate value of 1 segment
local green_zone = math.floor((bar_length_medium - initial_value) / one_segment) -- calculate the number of segments in the green zone
local yellow_zone = math.floor((bar_length_hot - initial_value) / one_segment) -- calculate the number of segments in the yellow zone
local red_zone = bar_length -- the remaining segments are for the red zone

local segment_count = math.floor((raw_value - initial_value) / one_segment) -- number of segments to display in bargraph


-- calculate the percentage value round to the nearest whole number
local percentage = (raw_value - initial_value) / (max_value - initial_value) * 100
if percentage < 0 then
percentage = 0
elseif percentage > 100 then
percentage = 100
end
local percentage_display = math.floor(percentage + 0.5)


-- building the separate bar segments
local green_bar = ''
local yellow_bar = ''
local red_bar = ''

if segment_count <= green_zone then
green_bar = '<span style="color: Green;">' .. string.rep('█', segment_count) .. '</span>' ..
'<span style="color: Wheat; background-color: Green;">' .. string.rep('▓', green_zone - segment_count) .. '</span>'
yellow_bar = '<span style="color: Wheat; background-color: yellow;">' .. string.rep('▓', yellow_zone - green_zone) .. '</span>'
red_bar = '<span style="color: Wheat; background-color: red;">' .. string.rep('▓', red_zone - yellow_zone) .. '</span>'
elseif segment_count > green_zone and segment_count <= yellow_zone then
green_bar = '<span style="color: Green;">' .. string.rep('█', green_zone) .. '</span>'
yellow_bar = '<span style="color: Yellow;">' .. string.rep('█', segment_count - green_zone) .. '</span>' ..
'<span style="color: Wheat; background-color: yellow;">' .. string.rep('▓', yellow_zone - segment_count) .. '</span>'
red_bar = '<span style="color: Wheat; background-color: red;">' .. string.rep('▓', red_zone - yellow_zone) .. '</span>'
elseif segment_count > yellow_zone then
green_bar = '<span style="color: Green;">' .. string.rep('█', green_zone) .. '</span>'
yellow_bar = '<span style="color: Yellow;">' .. string.rep('█', yellow_zone - green_zone) .. '</span>'
red_bar = '<span style="color: Red;">' .. string.rep('█', segment_count - yellow_zone) .. '</span>' ..
'<span style="color: Wheat; background-color: red;">' .. string.rep('▓', red_zone - segment_count) .. '</span>'
end

-- building the bar
local bar = '<span style="font-family: Consolas; font-weight: bold; font-size: 14px;">' ..
initial_value .. 'W' .. '▐' .. green_bar .. yellow_bar .. red_bar .. '▌' .. max_value .. 'W\n' ..
string.rep(' ', segment_count + 4) .. '▲\n' ..
string.rep(' ', segment_count) .. round_value .. '°W'.. percentage_display .. '%' .. '</span>'

-- check if the current message is same as the new message
local current_message = text_device.text
if (current_message ~= bar) then
text_device.updateText(bar) -- Update the text device

----------> automatically clear the log of the textdevice; change the ip and portnumber accordingly to your setup..
domoticz.openURL('http://127.17.0.2:80/json.htm?type=comm ... og&idx=689')
else
return -- This will stop the script and no log entry will be made
end
end
}

Re: Bargraph text-device

Posted: Saturday 25 May 2024 14:58
by RonkA
Funny you mention this; now i am making a bargraph to monitor the mains voltage and this has almost the same challenge as what you are attempting.
It is a bargraph that shows a bar to 2 sides, one negative, a 'neutral' point in the middle, and one positive side, so it ranges from 207 volt to 230 volt to 253 volt..
so if the voltage is under 230 volt there is a bargraph on the left and if the voltage is over 230 volt there is a bargraph to the right.
This is almost the same for your wattage bargraph but with much lower values..
I have the right side working (copy paste almost ;) ) and now trying to make the left side working..
The bandwith for the bargraph will be 253-207=46 volts at 30 segments gives a resolution of 1,53 volt per segment..
If it works it wil not be to hard to convert to your power bargraph.
The bandwidth of 6000 watt at 30 segments wil give a resolution 200 watt so it wil not be very accurate.

Re: Bargraph text-device

Posted: Saturday 25 May 2024 15:17
by rron
Ok I hope you will share it and then I can see what I did wrong. 8-)

Re: Bargraph text-device

Posted: Sunday 26 May 2024 18:14
by meal
Hello,

The bargraph implementation is a nice feature.

Would it be possible not to store the text log for a text device in order not to overload the domoticz DB ?

BR

Re: Bargraph text-device

Posted: Sunday 26 May 2024 21:22
by janpep
meal wrote: Sunday 26 May 2024 18:14 Would it be possible not to store the text log for a text device in order not to overload the domoticz DB ?
Indeed. Very nicely made. I am still thinking about possible use for myself :-)
About your log: i do not think you quickly overload the DB. How much grow do you expect?
If you are concerned about the amount of data to store you might want to use logging to a separate file?
Or create a function that clears the log for the device from time to time. Something like:

Code: Select all

dz.openURL('http://<IP>:<PORT>/json.htm?type=command&param=clearlightlog&idx=<INDEXNUMBER>')

Re: Bargraph text-device

Posted: Sunday 26 May 2024 22:32
by RonkA
meal wrote: Sunday 26 May 2024 18:14 Would it be possible not to store the text log for a text device in order not to overload the domoticz DB ?
Read line 75!!!!

Code: Select all

 ----------> automatically clear the log of the textdevice; change the ip and portnumber accordingly to your setup..
            domoticz.openURL('http://127.17.0.2:80/json.htm?type=command&param=clearlightlog&idx=335')