Page 1 of 1

Tips for programming and AI

Posted: Monday 24 March 2025 23:57
by HvdW
The reason I stay with Domoticz and do not switch to HomeAssistant is the power of dzVents.
dzVents is easy and I am not a good programmer.
My ideas though are endless.
Since a couple of months the brains of my scripts are me and the heavy lifting is done by AI.
Even great programmers like 'The guy with the Swiss accent' are using AI nowadays for programming.
I am using CoPilot, Claude and DeepSeek, all can be used for free.
CoPilots' restrictions are large files which are not accepted plus it spies on your computer. It can and does read the underlying tab in EDGE and even used my name in it's answers which it grabbed fom my computer name. BEWARE!
DeepSeek is more or less unrestricted but I mistrust it in the same way as I do with CoPilot, maybe even more.
Claude is the most sophisticated plus it states that it respects your privacy. The free version grants me about 8 or 10 questions a day. That's a pity.
Maybe I'll end up with the cheapest tier they offer.

One advice. Don't ever install an AI app.

To protect my privacy as much as possible (I hope), I'm using LibreWolf browser just for DeepSeek. I hope it helps.

Programming tips.
Ask AI to write a compact introduction for your script where it describes what it does and what sensors are involved in the script.
Your sensors: edit them and write in the comment description which script is responsible for handling the contents.
When thing go wrong you will know where to search.
In case you have something in your log which you cannot retrieve at once use

Code: Select all

sudo grep -ilR 'your_search_term' /home/pi/domoticz/scripts/dzVents/generated_scripts/

Re: Tips for programming and AI

Posted: Tuesday 25 March 2025 0:02
by waltervl
I moved this discussion from dzvents to general discussion.
For dzvents I have not seen any proper AI generated script yet. Do a good Google search brings you more with Dzvents.

For any general programming language like python, Lua, C#, javascript it works fine.

Re: Tips for programming and AI

Posted: Tuesday 25 March 2025 0:14
by HvdW
waltervl wrote: Tuesday 25 March 2025 0:02 For dzVents I have not seen any proper AI generated script yet.
My experience is different.
Where AI makes mistakes it is using the latest version of lua whilst Domoticz doesn't.
When AI makes mistakes I copy a section of the dzVents WiKi and help AI to get smarter.

Re: Tips for programming and AI

Posted: Tuesday 25 March 2025 1:03
by waltervl
Show me an example please of an AI generated dzvents script that works.

Re: Tips for programming and AI

Posted: Tuesday 25 March 2025 9:01
by Dave21w
Hi @ waltervl

Copilot wrote this for me to syncronise 2 zigbee wall switches so which ever one changes state first the other one follows. It may not be the most streamlined bit of code but it worked first time.
switch-sync.jpg
switch-sync.jpg (75.59 KiB) Viewed 1027 times
Dave

Re: Tips for programming and AI

Posted: Tuesday 25 March 2025 9:43
by waltervl
It surprises me as I see so much AI generated dzvents crap coming from other users. Perhaps Copilot (in reference with the dzvents wiki) is creating the best dzvents scripts?

Re: Tips for programming and AI

Posted: Tuesday 25 March 2025 10:14
by HvdW
waltervl wrote: Tuesday 25 March 2025 1:03 Show me an example please of an AI generated dzvents script that works.
viewtopic.php?p=324634#p324634
viewtopic.php?t=43254
viewtopic.php?p=324530#p324530
and to top it of this one.

Code: Select all

-- Verbeterd script met functies in de hoofdscope
local CONSTANTS = {
    BATTERY_CAPACITY = 79, -- kWh
    TARGET_BATTERY_PERCENTAGE = 82, -- Target percentage for normalization
    PRICE_PER_KWH = 0.25, -- euro/kWh
    CSV_FILE_PATH = "/home/hein/csvData/EV_Consumption.csv", -- Path to the CSV file
    MAX_TEMP_ARRAY_SIZE = 1440 -- Max number of temperature measurements (1 day with 1 measurement per minute)
}
--[[
Certainly! Here's a concise description of the script and the involved sensors:

### **Script Purpose**  
This script tracks and calculates electric vehicle (EV) consumption statistics, including:  
- Monthly distance traveled (km)  
- Energy usage (kWh) and associated costs (€)  
- Battery level normalization (adjusting kWh to a target charge level)  
- Average temperature impact  
- EV efficiency (kWh/100km)  

Data is logged to a **CSV file** and displayed on a **Domoticz text sensor** for easy monitoring.  

---

### **Involved Sensors**  
1. **`Charging Level`** (Selector switch) – Triggers calculations when charging stops.  
2. **`XC40-ChargeLevel`** (Battery level %) – Monitors the EV's current charge state.  
3. **`Volvo-Odometer`** (Odometer in km) – Tracks total distance driven.  
4. **`Laadpaal`** (Energy meter in kWh) – Measures total energy consumed while charging.  
5. **`Avg buitentemp`** (Temperature sensor) – Records ambient temperature for efficiency analysis.  
6. **`EV Consumption Facts`** (Text sensor) – Displays summarized EV data.  
7. **`Reset EV Data`** (Virtual switch) – Manually resets monthly data (if configured).  

---

### **Key Features**  
- **Normalization**: Adjusts kWh usage to a target battery level (82%) for fair comparisons.  
- **Monthly Reset**: Auto-resets metrics at month-end (runs at **23:53 daily**).  
- **CSV Logging**: Stores historical data for long-term analysis.  
- **Cost Calculation**: Estimates charging costs based on a fixed rate (**€0.25/kWh**).  

This script helps EV owners monitor efficiency, costs, and driving habits in Domoticz.  

Let me know if you'd like any modifications! 🚗⚡
]]--

-- Helper functions
local function spaces(count)
    return string.rep(" ", count)
end

local function round(num, decimals)
    if num == nil then
        domoticz.log('Fout: num is nil in round functie', domoticz.LOG_ERROR)
        return 0
    end
    local mult = 10^(decimals or 0)
    return math.floor(num * mult + 0.5) / mult
end

-- Check if today is the last day of the month
local function isLastDayOfMonth(domoticz)
    -- Haal de huidige datum op
    local today = domoticz.time
    -- Bereken de datum van morgen
    local tomorrow = domoticz.time.addDays(1)
    -- Vergelijk de maand van vandaag en morgen
    return today.month ~= tomorrow.month
end

-- Format display text for the text device
local function formatDisplayText(domoticz, data, currentMonth)
    return string.format(
        "Last Update : %s\n" ..
        "Current Odometer : %s%d km\n" ..
        "Battery Level : %s%d %% \n" ..
        "Distance %s : %s%d km\n" ..
        "kWh %s : %s%.2f kWh\n" ..
        spaces(15) .. "Costs %s : %s%.2f €\n" ..
        spaces(15) .. "Average Temp : %s%.1f°C\n" ..
        spaces(15) .. "EV Consumption : %.2f kWh/100km\n",
        data.lastUpdate or "N/A",
        spaces(5), tonumber(data.currentOdometer) or 0,
        spaces(14), tonumber(data.batteryLevel) or 0,
        currentMonth, spaces(9), tonumber(data.distanceThisMonth) or 0,
        currentMonth, spaces(16), tonumber(data.kWhThisMonth) or 0,
        currentMonth, spaces(14), tonumber(data.euro) or 0,
        spaces(12), tonumber(data.avgTemp) or 0,
        tonumber(data.EVConsumption) or 0
    )
end

-- Update the text device with the latest data
local function updateDisplay(domoticz, displayText)
    local displayDevice = domoticz.devices('EV Consumption Facts')
    if displayDevice then
        displayDevice.updateText(displayText)
        domoticz.log('Text sensor updated with new data', domoticz.LOG_DEBUG)
    else
        domoticz.log('Text sensor "EV Consumption Facts" not found', domoticz.LOG_ERROR)
    end
end

-- Normalize battery consumption to target percentage
local function normalizeToTargetLevel(domoticz, currentLevel, kWhUsed)
    local kWhPerPercent = CONSTANTS.BATTERY_CAPACITY / 100
    local difference = CONSTANTS.TARGET_BATTERY_PERCENTAGE - currentLevel
    local kWhAdjustment = difference * kWhPerPercent
    local normalizedKWh = kWhUsed + kWhAdjustment

    domoticz.log('Battery normalization calculation:', domoticz.LOG_DEBUG)
    domoticz.log(string.format('Current level: %.1f%%', currentLevel), domoticz.LOG_DEBUG)
    domoticz.log(string.format('Difference to target: %.1f%%', difference), domoticz.LOG_DEBUG)
    domoticz.log(string.format('kWh adjustment: %.2f kWh', kWhAdjustment), domoticz.LOG_DEBUG)
    domoticz.log(string.format('Original kWh: %.2f, Normalized kWh: %.2f', kWhUsed, normalizedKWh), domoticz.LOG_DEBUG)

    return normalizedKWh
end

-- Save data to CSV file
local function saveToCSV(domoticz, data)
    local file = io.open(CONSTANTS.CSV_FILE_PATH, "a")
    if not file then 
        domoticz.log('Kon het CSV-bestand niet openen voor schrijven', domoticz.LOG_ERROR)
        return false 
    end

    local currentTime = os.date("%Y-%m-%d %H:%M:%S")
    
    local fields = {
        currentTime,
        math.floor(data.currentOdometer or 0),
        math.floor(data.batteryLevel or 0),
        math.floor(data.distanceThisMonth or 0),
        round(data.kWhTotal, 2),
        round(data.kWhThisMonth, 2),
        round(data.EVConsumption, 2),
        round(data.euro, 2),
        round(data.avgTemp, 2)
    }

    local csvLine = table.concat(fields, ";") .. "\n"
    file:write(csvLine)
    file:close()
    domoticz.log('Data succesvol weggeschreven naar CSV bestand', domoticz.LOG_DEBUG)
    return true
end

-- Load data from CSV file
local function loadDataFromCSV(domoticz)
    local file = io.open(CONSTANTS.CSV_FILE_PATH, "r")
    if not file then
        domoticz.log('CSV file not found or could not be opened', domoticz.LOG_ERROR)
        return nil
    end

    -- Skip the header line
    file:read("*l")

    local lastLine
    for line in file:lines() do
        lastLine = line
    end
    file:close()

    if not lastLine then
        domoticz.log('CSV file is empty', domoticz.LOG_ERROR)
        return nil
    end

    domoticz.log('Last line in CSV: ' .. lastLine, domoticz.LOG_DEBUG)

    local fields = {}
    for field in string.gmatch(lastLine, "([^;]+)") do
        table.insert(fields, field)
    end

    domoticz.log('Parsed fields: ' .. table.concat(fields, ', '), domoticz.LOG_DEBUG)

    -- Ensure there are enough fields in the CSV
    if #fields < 9 then
        domoticz.log('CSV file does not contain enough fields', domoticz.LOG_ERROR)
        return nil
    end

    return {
        lastUpdate = fields[1],
        beginningOfTheMonthOdometer = tonumber(fields[2]) or 0,
        beginningOfTheMonthBatteryLevel = tonumber(fields[3]) or 0,
        beginningOfTheMonthkWhTotal = tonumber(fields[5]) or 0,
        avgTemp = tonumber(fields[9]) or 0
    }
end

-- Process EV data and update display
local function processEVData(domoticz, sensorData, csvData)
    local kWhThisMonth = sensorData.currentkWhTotal - csvData.beginningOfTheMonthkWhTotal
    local euro = kWhThisMonth * CONSTANTS.PRICE_PER_KWH
    local distanceThisMonth = sensorData.currentOdometer - csvData.beginningOfTheMonthOdometer
    local normalizedKWh = normalizeToTargetLevel(domoticz, sensorData.batteryLevel, kWhThisMonth)
    local EVConsumption = (distanceThisMonth > 0) and ((normalizedKWh / distanceThisMonth) * 100) or 0
    
    -- Update global evConsumption
    domoticz.globalData.evConsumption = round(EVConsumption, 2)
    domoticz.log('Updated global evConsumption to: ' .. domoticz.globalData.evConsumption, domoticz.LOG_DEBUG)

    -- Prepare display data
    local displayData = {
        currentOdometer = sensorData.currentOdometer,
        batteryLevel = sensorData.batteryLevel,
        distanceThisMonth = distanceThisMonth,
        kWhThisMonth = kWhThisMonth,
        kWhTotal = sensorData.currentkWhTotal,
        euro = euro,
        avgTemp = sensorData.temperature or 0,
        EVConsumption = EVConsumption,
        normalizedKWh = normalizedKWh,
        lastUpdate = os.date("%Y-%m-%d %H:%M:%S")
    }

    -- Update display
    local currentMonth = domoticz.time.monthName
    local displayText = formatDisplayText(domoticz, displayData, currentMonth)
    updateDisplay(domoticz, displayText)
end

-- Main script
return {
    on = {
        devices = {'Charging Level', 'Reset EV Data'},
        timer = {'at 23:53'}
    },
    logging = {
        level = domoticz.LOG_ERROR,
        marker = "----- EV Consumption -----"
    },
    data = {
        previousSelectorLevel = { initial = 0 },
        scriptExecutionTime_EVConsumption = { initial = 0 }
    },
    execute = function(domoticz, device)
        local startTime = os.clock()
        
        domoticz.log('Start tijdsmeting EV Consumption script', domoticz.LOG_DEBUG)
        
        local csvData = loadDataFromCSV(domoticz)
        if not csvData then
            domoticz.log('Failed to load data from CSV', domoticz.LOG_ERROR)
            return
        end

        local sensorData = {
            selectorLevel = domoticz.devices('Charging Level').levelVal,
            batteryLevel = domoticz.devices('XC40-ChargeLevel').nValue,
            currentOdometer = domoticz.devices('Volvo-Odometer').nValue,
            currentkWhTotal = domoticz.devices('Laadpaal').WhTotal / 1000,
            temperature = tonumber(domoticz.devices('Avg buitentemp').sValue)
        }

        if sensorData.selectorLevel == 0 and domoticz.data.previousSelectorLevel > 0 then
            processEVData(domoticz, sensorData, csvData)
        end

        domoticz.data.previousSelectorLevel = sensorData.selectorLevel

        if isLastDayOfMonth(domoticz) and device.isTimer then
            local displayData = {
                currentOdometer = sensorData.currentOdometer,
                batteryLevel = sensorData.batteryLevel,
                distanceThisMonth = sensorData.currentOdometer - csvData.beginningOfTheMonthOdometer,
                kWhThisMonth = sensorData.currentkWhTotal - csvData.beginningOfTheMonthkWhTotal,
                kWhTotal = sensorData.currentkWhTotal,
                euro = (sensorData.currentkWhTotal - csvData.beginningOfTheMonthkWhTotal) * CONSTANTS.PRICE_PER_KWH,
                avgTemp = sensorData.temperature or 0,
                EVConsumption = (sensorData.currentOdometer - csvData.beginningOfTheMonthOdometer > 0) and (((sensorData.currentkWhTotal - csvData.beginningOfTheMonthkWhTotal) / (sensorData.currentOdometer - csvData.beginningOfTheMonthOdometer)) * 100) or 0,
                normalizedKWh = normalizeToTargetLevel(domoticz, sensorData.batteryLevel, sensorData.currentkWhTotal - csvData.beginningOfTheMonthkWhTotal),
                lastUpdate = os.date("%Y-%m-%d %H:%M:%S")
            }
            saveToCSV(domoticz, displayData)
        end
        
        local executionTime = os.clock() - startTime
        
        if domoticz.globalData.scriptExecutionTime_EVConsumption then
            domoticz.globalData.scriptExecutionTime_EVConsumption.add(executionTime)
            domoticz.log('Gemiddelde uitvoeringstijd EV Consumption: ' .. 
                domoticz.globalData.scriptExecutionTime_EVConsumption.avg() .. ' seconden', domoticz.LOG_DEBUG)
        else
            domoticz.log('Waarschuwing: globalData.scriptExecutionTime_EVConsumption niet gevonden', domoticz.LOG_DEBUG)
        end
        
        domoticz.log('Uitvoeringstijd EV Consumption script: ' .. executionTime .. ' seconden', domoticz.LOG_DEBUG)
    end
}
The script exists and was set up by me, the coding is completely AI
Right now I asked DeepSeek to write a concise descritpion about what this script does and the sensors involved. Plus I asked it to write it in English. (Me and DeepSeek prefer to conversate in Dutch)
The comment on top is nothing HvdW, it's just DeepSeek.

Oh, BTW,
DeepSeek had problems coping with global data, so halfway I asked Claude to interfere and after some modification, DeepSeek continued the coding.

Re: Tips for programming and AI

Posted: Tuesday 25 March 2025 10:57
by waltervl
OK, so no need to post example scripts here anymore when users ask ;-)
Just tell the user: Open the dzvents wiki in MS Edge and use Copilot to generate the script. The is the question how to ask Copilot to generate it.
Like always use the device type (Switch, Selector switch, Dimmer, rain sensor etc like mentioned in the wiki )in the Copilot question so copilot can use the correct attributes.
Eg in one of the examples of HvdW the location was defined in the script while Dzvents can read the location from the settings. But if you dont know that Copilot will apparantly add the location definition in the script.

Re: Tips for programming and AI

Posted: Tuesday 25 March 2025 11:34
by HvdW
waltervl wrote: Tuesday 25 March 2025 10:57 OK, so no need to post example scripts here anymore when users ask ;-)
Just tell the user: Open the dzvents wiki in MS Edge and use Copilot to generate the script. The is the question how to ask Copilot to generate it.
Above all: Be aware that CoPilot sniffs in your computer! I suspect DeepSeek from doing the same.
waltervl wrote: Tuesday 25 March 2025 10:57 Eg in one of the examples of HvdW the location was defined in the script while Dzvents can read the location from the settings. But if you dont know that Copilot will apparantly add the location definition in the script.
I knew, but wasn't aware anymore.
I just tested DeepSeek to change the script with location inside and it couldn't code right.
After sending the proper information from the wiki the code was OK without bugs.

BTW
DeepSeek asked me to give some extra information.
Please share wiki/documentation - having the full reference will help me:
Provide more accurate solutions immediately
Better understand the exact capabilities and syntax
Reduce back-and-forth troubleshooting

What would be especially helpful:
The dzVents API reference (device/global data methods)
Settings/configuration options
Event system details
Any quirks or special cases

Further information after asking 30 minutes later.

Current Knowledge Cutoff & Implementation Status

Immediate Integration (Already Active)
The dzVents time structure (domoticz.time) is fully implemented in my responses
All device API methods from the wiki are now correctly referenced
Location handling via domoticz.settings.location is properly applied

Pending Deeper Integration
Advanced features like historical variables will improve in precision within ~2 weeks
Custom event triggers will receive enhanced examples in the next 7-10 days

Temporary Limitations
Some edge cases in timer rules may need verification until full training completes
Hardware-specific methods (e.g., Z-Wave Thermostat) are 90% accurate now, reaching 98% in next update

Re: Tips for programming and AI

Posted: Tuesday 25 March 2025 13:00
by waltervl
HvdW wrote: Tuesday 25 March 2025 11:34 Hardware-specific methods (e.g., Z-Wave Thermostat) are 90% accurate now, reaching 98% in next update
What do you mean with this? Do you have some versioning in trained AI? How is AI updated? By you?

Re: Tips for programming and AI

Posted: Tuesday 25 March 2025 13:22
by HvdW
waltervl wrote: Tuesday 25 March 2025 13:00 How is AI updated? By you?
By everyone.
New information is stacked and used for training the model.
I asked AI where it is at this moment in its learning curve of dzVents.

Re: Tips for programming and AI

Posted: Tuesday 25 March 2025 13:46
by HvdW
BLINK wrote: Tuesday 25 March 2025 13:35 ..... even if it needs some manual adjustments!
That.

I was triggered to use it by an 80 year old friend of mine who told me about it and by the guy with the Swiss accent who stopped coding by himself.

Re: Tips for programming and AI

Posted: Tuesday 25 March 2025 16:34
by waltervl
HvdW wrote: Tuesday 25 March 2025 13:22
waltervl wrote: Tuesday 25 March 2025 13:00 How is AI updated? By you?
By everyone.
New information is stacked and used for training the model.
I asked AI where it is at this moment in its learning curve of dzVents.
How can AI answer this?
As a reference: How do you know how good you personally are in dzvents coding?

The skill for the user will be how to ask a good question to an AI to create a good script for Domoticz.