Page 1 of 1

Request: 3 phase voltage device

Posted: Saturday 10 October 2026 21:26
by JanJaap
Hi,

Would it be possible to add a 3 phase voltage device, similar to the 3 phase current device? It is a bit clumsy to have 3 individual devcices for Voltage where the one for current is much more elegant

Re: Request: 3 phase voltage device

Posted: Saturday 10 October 2026 23:22
by imautohuttraeger
Good Point. I also miss this. And 3 phase power devices would also be helpful.

Re: Request: 3 phase voltage device

Posted: Monday 12 October 2026 23:27
by RonkA
Not what you are asking exactly but this is my good old text-device workaround.. Maybe an inspiration for Gizmocuz 8-)
The script is usable for 1,2 and 3 phase voltages..

Code: Select all

-- Voltage Bargraph maker for text device -- RonkA

return {
    on = {
        timer = {'at 23:59'},

        devices = {27} -->-->-->- set correct idx number of P1_device   
        
    },

    data = {
        min_voltage_L1 = { initial = 229.9 }, -- Initialize the min_voltage_L1 variable; for 120v mains set to 119.9
        min_voltage_L2 = { initial = 229.9 }, -- Initialize the min_voltage_L2 variable; for 120v mains set to 119.9
        min_voltage_L3 = { initial = 229.9 }, -- Initialize the min_voltage_L3 variable; for 120v mains set to 119.9
        max_voltage_L1 = { initial = 230 }, -- Initialize the max_voltage_L1 variable; for 120v mains set to 120.1
        max_voltage_L2 = { initial = 230 }, -- Initialize the max_voltage_L2 variable; for 120v mains set to 120.1
        max_voltage_L3 = { initial = 230 }, -- Initialize the max_voltage_L3 variable; for 120v mains set to 120.1
    },  

--[[    logging = {
        level = domoticz.LOG_ERROR,
        marker = 'Bargraph',
    },
]]
    execute = function(domoticz, device)
-->-->-->- values are set for 230 volt mains with a 10% tolerance according to NEN-EN 50160
        -- for 120 volt mains with a 5% tolerance (ANSI standard) adjust values accordingly 
-- domoticz.log('Bargraph - Net - Voltages ' .. device.name, domoticz.LOG_INFO)       
        local padding = 7               -- number of invisible blocks to allign the 2nd and 3rd bargraph in the textdevice          
        local bar_length = 17           -- number of segments in bargraph       - for 120 volts mains 
        local low_value = 207           -- begin value of the low red zone      - 114
        local low_red_value = 212       -- value to start the low red zone      - 116
        local low_yellow_value = 220    -- value to start the low yellow zone   - 118
        local mid_value = 230           -- middle of green zone                 - 120
        local high_yellow_value = 240   -- value to start the high yellow zone  - 122
        local high_red_value = 248      -- value to start the high red zone     - 124
        local high_value = 253          -- end value of the high red zone       - 126

        -- fictional values if less than 3 phase are used.. do not remove!       
        local voltageL2 = 231
        local voltageL3 = 231        

-->-->-->- for 1 phase metering only use voltageL1; voltageL2 and voltageL3 have to be commented out! (set -- in front of local..)
        -- for 2 phase metering only use voltageL1 and voltageL2; voltageL3 has to be commented out!
        -- set correct idx number of voltage device(s) 
        local voltageL1 = domoticz.utils.round(domoticz.devices(28).voltage,1)
        local voltageL2 = domoticz.utils.round(domoticz.devices(29).voltage,1)
        local voltageL3 = domoticz.utils.round(domoticz.devices(30).voltage,1)
        


-->-->-->- idx number of the textdevice; change accordingly
        local text_device = domoticz.devices(337)  
        
        -- initialize min and max voltage values
        local voltageL1_min = domoticz.data.min_voltage_L1
        local voltageL2_min = domoticz.data.min_voltage_L2
        local voltageL3_min = domoticz.data.min_voltage_L3
        local voltageL1_max = domoticz.data.max_voltage_L1
        local voltageL2_max = domoticz.data.max_voltage_L2
        local voltageL3_max = domoticz.data.max_voltage_L3

        -- store value when voltage is lower or higer than the stored min or max voltage
        if voltageL1 < mid_value and voltageL1 < voltageL1_min then
            domoticz.data.min_voltage_L1 = voltageL1
        end
        if voltageL2 < mid_value and voltageL2 < voltageL2_min then
            domoticz.data.min_voltage_L2 = voltageL2
        end
        if voltageL3 < mid_value and voltageL3 < voltageL3_min then
            domoticz.data.min_voltage_L3 = voltageL3
        end
        if voltageL1 > mid_value and voltageL1 > voltageL1_max then
            domoticz.data.max_voltage_L1 = voltageL1
        end
        if voltageL2 > mid_value and voltageL2 > voltageL2_max then
            domoticz.data.max_voltage_L2 = voltageL2
        end
        if voltageL3 > mid_value and voltageL3 > voltageL3_max then
            domoticz.data.max_voltage_L3 = voltageL3
        end
        
        -- check if it's nighttime (23:59) to reset bargraph variables
        if (device.isTimer) then
            domoticz.log('Reset Bargraph Voltage Variables', domoticz.LOG_INFO)
            domoticz.data.min_voltage_L1 = 229.9
            domoticz.data.min_voltage_L2 = 229.9
            domoticz.data.min_voltage_L3 = 229.9
            domoticz.data.max_voltage_L1 = 230
            domoticz.data.max_voltage_L2 = 230
            domoticz.data.max_voltage_L3 = 230
	        return 
		end
		
        -- function to take (value) and make half a bargraph in the correct manner.
        --if value is lower than mid_value bargraph from right to left and if value is higher than mid_value from left to right 
        local function createBargraph(value)
        local one_segment = (high_value - low_value) / (2 * bar_length)
    
        local low_green_zone = math.abs(math.floor((low_yellow_value - mid_value) / one_segment))
        local low_yellow_zone = math.abs(math.floor((low_red_value - mid_value) / one_segment))
        local low_red_zone = bar_length
    
        local high_green_zone = math.floor((high_yellow_value - mid_value) / one_segment)
        local high_yellow_zone = math.floor((high_red_value - mid_value) / one_segment)
        local high_red_zone = bar_length
    
        local text_value = value
        
        -- stop value to get lower or higher than outer values of bargraph     
        if value < low_value then 
            value = low_value         
        elseif value > high_value then 
            value = high_value        
        end
        
        -- determine if value is lower or higer than mid_value
        local segment_count = math.abs(math.floor((value - mid_value) / one_segment))
        local is_below_mid = value < mid_value
        local bar = ''
    
        if is_below_mid then
            segment_count_low = bar_length - math.floor((mid_value - value) / one_segment)
        
            -- building the separate bar segments when value is lower than mid_value
            local green_bar = ''
            local yellow_bar = ''
            local red_bar = ''

            if segment_count_low > low_red_zone then 
                green_bar = '<span style="color: green;">' .. string.rep('■', low_green_zone) .. '</span>'
                yellow_bar = '<span style="color: yellow">' .. string.rep('■', low_yellow_zone - low_green_zone) .. '</span>'
                red_bar = '<span style="color: Red;">' .. string.rep('■', low_red_zone - low_yellow_zone) .. '</span>'
            elseif segment_count_low > low_green_zone then 
                green_bar = '<span style="color: #CCFDA9 ;">' .. string.rep('■', low_green_zone - segment_count) .. '</span>' ..
                            '<span style="color: Green;">' .. string.rep('■', segment_count) .. '</span>'
                yellow_bar = '<span style="color: #F4FDA9 ;">' .. string.rep('■', low_yellow_zone - low_green_zone) .. '</span>'
                red_bar = '<span style="color: #FDD2A9;">' .. string.rep('■', low_red_zone - low_yellow_zone) .. '</span>' 
            elseif segment_count_low <= low_green_zone and segment_count_low > low_yellow_zone - low_green_zone then 
                green_bar = '<span style="color: Green;">' .. string.rep('■', low_green_zone) .. '</span>'
                yellow_bar = '<span style="color: #F4FDA9 ;">' .. string.rep('■', low_yellow_zone - segment_count) .. '</span>' ..
                             '<span style="color: Yellow;">' .. string.rep('■', segment_count - low_green_zone) .. '</span>'
                red_bar = '<span style="color: #FDD2A9;">' .. string.rep('■', low_red_zone - low_yellow_zone) .. '</span>'
            elseif segment_count_low <= low_red_zone - low_yellow_zone then
                green_bar = '<span style="color: Green;">' .. string.rep('■', low_green_zone) .. '</span>'
                yellow_bar = '<span style="color: Yellow;">' .. string.rep('■', low_yellow_zone - low_green_zone) .. '</span>'
                red_bar = '<span style="color: #FDD2A9;">' .. string.rep('■', low_red_zone - segment_count) .. '</span>' ..
                          '<span style="color: Red;">' .. string.rep('■', segment_count - low_yellow_zone) .. '</span>'
            end
            -- assemble bar        
            bar = '◄' .. red_bar .. yellow_bar .. green_bar .. '►' 

        else
            -- Building the separate bar segments when value is higher than mid_value
            local green_bar = ''
            local yellow_bar = ''
            local red_bar = ''
        
            if segment_count <= high_green_zone then
                green_bar = '<span style="color: Green;">' .. string.rep('■', segment_count) .. '</span>' ..
                            '<span style="color: #CCFDA9 ;">' .. string.rep('■', high_green_zone - segment_count) .. '</span>'
                yellow_bar = '<span style="color: #F4FDA9 ;">' .. string.rep('■', high_yellow_zone - high_green_zone) .. '</span>'
                red_bar = '<span style="color: #FDD2A9 ;">' .. string.rep('■', high_red_zone - high_yellow_zone) .. '</span>'
            elseif segment_count > high_green_zone and segment_count <= high_yellow_zone then -- 13>7= ok 13<=11=not
                green_bar = '<span style="color: Green;">' .. string.rep('■', high_green_zone) .. '</span>'
                yellow_bar = '<span style="color: Yellow;">' .. string.rep('■', segment_count - high_green_zone) .. '</span>' ..
                             '<span style="color: #F4FDA9 ;">' .. string.rep('■', high_yellow_zone - segment_count) .. '</span>'
                red_bar = '<span style="color: #FDD2A9 ;">' .. string.rep('■', high_red_zone - high_yellow_zone) .. '</span>'
            elseif segment_count > high_yellow_zone then --13>11=ok
                green_bar = '<span style="color: Green;">' .. string.rep('■', high_green_zone) .. '</span>'
                yellow_bar = '<span style="color: Yellow;">' .. string.rep('■', high_yellow_zone - high_green_zone) .. '</span>'
                red_bar = '<span style="color: Red;">' .. string.rep('■', segment_count - high_yellow_zone) .. '</span>' ..
                          '<span style="color: #FDD2A9 ;">' .. string.rep('■', high_red_zone - segment_count) .. '</span>'
            elseif segment_count > high_red_zone then
                green_bar = '<span style="color: Green;">' .. string.rep('■', high_green_zone) .. '</span>'
                yellow_bar = '<span style="color: Yellow;">' .. string.rep('■', high_yellow_zone - high_green_zone) .. '</span>'
                red_bar = '<span style="color: Red;">' .. string.rep('■', segment_count - high_yellow_zone) .. '</span>'
            end
            -- assemble bar
            bar = '◄' .. green_bar .. yellow_bar .. red_bar .. '►'
        end
        return bar
    end 
    
-- the next 2 functions create the texts around the bargraph(s).
-- when the bar_length is altered or if there is a mismach between the bargraph and the numbers..
-- this can be adjusted by changing the number after the word 'segment_count'..  a lower value wil adjust to the left 
-- the adjustment has to be done 4 times per function
-- an easy way to test is by giving a fixed known value to voltageL1 like 200; 229.9; 230,1; 260
-- something like: local voltageL1 = 200 --domoticz.utils.round(domoticz.devices(28).voltage,1) in the beginning of the script
-- after all done remove the '200 --' but that should be obvious...
-- resetting the bargraph can be done by removing bargraph volt.lua file from the domoticz\scripts\dzVents\data directory (in my docker enviroment..)
-- this can be helpfull to do after the adjustments as discribed above or if there was a power outage.. 
-- or just wait till the day is over, than all values are reset to the initial ones

        -- function to get the bottom bar to be displayed at the correct place 
        local function create_bottom_bar(value_posd, blocks)
        bottom_bar_arrow  = ''
        bottom_bar_value  = ''
        blockpad = string.rep(' ', blocks)
        value = value_posd       
        -- stop value to get lower or higher than outer values of bargraph        
        if value_posd < mid_value and value_posd < low_value then
            value_posd = low_value end
        if value_posd > mid_value and value_posd > high_value then
            value_posd = high_value end   
        local one_segment = (high_value - low_value) / (2 * bar_length)
        local segment_count = math.abs(math.floor((value_posd - low_value) / one_segment))
        if value_posd < mid_value then        
            --  when value_posd is lower than mid_value   
            if (segment_count - 2) < (bar_length / 2) then 
                -- value on right side of arrow like ▲ 218.4V
                -- bar_length is 17 = segment_count + 1; + 1
                -- bar_length is 15 = segment_count + 1; + 1
                -- bar_length is 13 = segment_count + 1; + 1
                bottom_bar_arrow = string.rep(' ', segment_count + 1) .. '▲'
				bottom_bar_value = string.rep(' ', segment_count + 1) .. '⁞ <span style="background-color: Aquamarine;">' .. domoticz.utils.round(value ,1) .. 'V</span>' 
            else
                 -- value on left side of arrow like 228.7V ▲ 
                 -- bar_length is 17 = segment_count + 1; - 6
                 -- bar_length is 15 = segment_count + 1; - 6
                 -- bar_length is 13 = segment_count + 1; - 6
                 bottom_bar_arrow = string.rep(' ', segment_count + 1).. '▲'
				 bottom_bar_value = string.rep(' ', segment_count - 6) .. '<span style="background-color: Aquamarine;">' .. domoticz.utils.round(value,1) .. 'V</span> ⁞'
            end
        else 
            --  when value_posd is higher than mid_value
            if bar_length >= segment_count - 6   then
                -- value on right side of arrow like ▲ 231.3V
                -- bar_length is 17 = segment_count + 5; + 5
                -- bar_length is 15 = segment_count + 4; + 4
                -- bar_length is 13 = segment_count + 4; + 4
                bottom_bar_arrow = string.rep(' ', segment_count + 5) .. '▲'
				bottom_bar_value = string.rep(' ', segment_count + 5) .. '⁞ <span style="background-color: Aquamarine;">' ..  domoticz.utils.round(value,1) .. 'V</span>' 
            else
                -- value on left side of arrow like 248.2V ▲
                -- bar_length is 17 = segment_count + 4; - 3
                -- bar_length is 15 = segment_count + 4; - 3
                -- bar_length is 13 = segment_count + 4; - 3
                bottom_bar_arrow = string.rep(' ', segment_count + 4) .. '▲'
				bottom_bar_value = string.rep(' ', segment_count - 3) .. '<span style="background-color: Aquamarine;">' .. domoticz.utils.round(value,1) .. 'V</span> ⁞'
            end
        end
        return blockpad .. bottom_bar_arrow .. '\n' .. blockpad .. bottom_bar_value
        end


    
         -- function to get the historic values to be displayed at the correct place swapping the place of the arrow and value if necessary         
        local function create_top_bar(value_posu)
            
            -- stop value to get lower or higher than outer values of bargraph 
           value = value_posu     
            if value_posu < mid_value and value_posu < low_value then
                value_posu = low_value end
            if value_posu > mid_value and value_posu > high_value then
                value_posu = high_value end             
            local one_segment = (high_value - low_value) / (2 * bar_length)
            local segment_count = math.abs(math.floor((value_posu - low_value) / one_segment))
            if value_posu < mid_value then 
                --  when value_posu is lower than mid_value
                if segment_count < bar_length / 2 then 
                    -- value on right side of arrow = ▼ 208.8
                    -- bar_length is 17 = segment_count + 1 and segment_count - 4 
                    -- bar_length is 15 = segment_count + 1 and segment_count - 4
                    -- bar_length is 13 = segment_count + 1 and segment_count - 4
                    top_bar = string.rep(' ', segment_count + 1) .. '▼ ' ..  domoticz.utils.round(value,1) .. 'V' .. string.rep(' ', (bar_length - segment_count) -4)
                else  
                    -- value on left side of arrow = 226.1V ▼
                    -- bar_length is 17 = segment_count - 6 and segment_count +3
                    -- bar_length is 15 = segment_count - 6 and segment_count +3
                    -- bar_length is 13 = segment_count - 6 and segment_count +3
                    top_bar = string.rep(' ', segment_count - 6) ..  domoticz.utils.round(value,1) .. 'V ▼' .. string.rep(' ', (bar_length - segment_count) +3)
                end
            else 
                -- when value_posu is higher than mid_value
                if bar_length >= segment_count - 8  then
                    -- value on right side of arrow = ▼ 241.8V
                    -- bar_length is 17 = segment_count - 18
                    -- bar_length is 15 = segment_count - 16
                    -- bar_length is 13 = segment_count - 14
                    top_bar = string.rep(' ', segment_count - 18) .. '▼ ' ..  domoticz.utils.round(value,1) .. 'V'
                else
                    -- value on left side of arrow = 250.5V ▼
                    -- bar_length is 17 = segment_count - 25
                    -- bar_length is 15 = segment_count - 23
                    -- bar_length is 13 = segment_count - 21
                    top_bar = string.rep(' ', segment_count - 25) ..  domoticz.utils.round(value,1) .. 'V ▼'
                end 
            end
            return top_bar        
        end  
        -- create invisible blocks to allign the 2nd and 3rd bargraph in the textdevice 
        padd = string.rep(' ', padding)
    
-->-->-->- building bargraph
        -- when using 1 phase comment the 2nd and 3rd "local bargraph" line out! (set -- in front of local..)
        -- when using 2 phase comment the 3rd "local bargraph line" out!
        local bargraph = create_top_bar(voltageL1_min) .. create_top_bar(voltageL1_max) .. '\n' .. createBargraph(voltageL1_min) .. 'L1' .. createBargraph(voltageL1_max) .. '\n' .. create_bottom_bar(voltageL1, 0) .. '\n' 
        local bargraph = bargraph ..'――――――――――――――――――――――――――――――――――――――――\n' .. padd .. create_top_bar(voltageL2_min) .. create_top_bar(voltageL2_max) .. '\n' .. padd  .. createBargraph(voltageL2_min) .. 'L2' .. createBargraph(voltageL2_max) .. '\n' ..  create_bottom_bar(voltageL2, padding) .. '\n'
        local bargraph = bargraph .. padd .. '――――――――――――――――――――――――――――――――――――――――\n'.. padd .. create_top_bar(voltageL3_min) .. create_top_bar(voltageL3_max) .. '\n' .. padd  .. createBargraph(voltageL3_min) .. 'L3' .. createBargraph(voltageL3_max) .. '\n'.. create_bottom_bar(voltageL3, padding)

        -- giving the bargraph the correct font and settings
        local final_bar = '<span style="font-family: Consolas; font-weight: bold; font-size: 13px;">' .. bargraph .. '</span>' 

        -- update text_device
        text_device.updateText(final_bar)
    
-->-->-->- Clear the log of the textdevice, put in the right idx of the textdevice!!  
        domoticz.openURL('http://127.17.0.2:80/json.htm?type=command&param=clearlightlog&idx=337')  
    end

}
it gives this:
voltages.GIF
voltages.GIF (38.86 KiB) Viewed 90 times
Before use Read! and adjust all devices marked by -->-->-->- (so 5 things..) in the script!!
Last one is specific; i run Domoticz in a Docker container on my Synology-nas, I don't know your ip-adres and port, (could be as simple as 192.168.1.xxx:80)