Posts: 41 
	Threads: 9 
	Joined: Jan 2016
	
 Reputation: 
 0
	 
 
	
	
		I have tried to make an outside compensation curve for a heating system in the FB editor, but do not find out completely of unwanted blocks that are most powerful to use. 
I need to write from four groups 
-10 ° C = 45 ° C 
-5 ° C = 40 ° C 
0 ° C = 35 ° C 
5 ° C = 30 ° C 
In order to get a set point out of what outdoor temperature it is, is this possible?
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 8422 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
 481
	 
 
	
	
		Do you really need a curve here? From your data it looks like simple linear compensation, for each 5 degrees of temperature the setpoint is lowered by 5 degrees: 
Code: setpoint = 35 - temperature
  
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 41 
	Threads: 9 
	Joined: Jan 2016
	
 Reputation: 
 0
	 
 
	
	
		Yes wee need a curve besause all values is going to be able to change in the visualizatione
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 8422 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
 481
	 
 
 
	
	
	
		
	Posts: 5287 
	Threads: 29 
	Joined: Aug 2017
	
 Reputation: 
 237
	 
 
	
	
		There is block in match advance curve function with 2 points, it might be good starting point.
	 
	
	
------------------------------ 
Ctrl+F5
 
	
		
	 
 
 
	
	
	
		
	Posts: 29 
	Threads: 6 
	Joined: Jan 2016
	
 Reputation: 
 4
	 
 
	
	
		Hello. 
You can try this:
 Code: function linear_by_table(input,curve,offset) 
local FDY = offset or 0  
    fk1= (curve["y"][1] - curve["y"][2]) / (curve["x"][1] - curve["x"][2]) 
    fk2= (curve["y"][2] - curve["y"][3]) / (curve["x"][2] - curve["x"][3]) 
    fk3= (curve["y"][3] - curve["y"][4]) / (curve["x"][3] - curve["x"][4]) 
 
    if input < curve["x"][1] then 
        out = curve["y"][1] + FDY; 
    elseif input >= curve["x"][1] and input < curve["x"][2] then     
        out = fk1 * (input - curve["x"][1]) + curve["y"][1] + FDY 
    elseif input >= curve["x"][2] and input < curve["x"][3] then 
        out = fk2 * (input - curve["x"][2]) + curve["y"][2] + FDY 
    elseif input >= curve["x"][3] and input < curve["x"][4] then     
        out = fk3 * (input - curve["x"][3]) + curve["y"][3] + FDY 
    else 
        out = curve["y"][4] + FDY 
    end 
  return out 
end 
 
curve = {} 
curve["x"] = {-20,-10,0,20} 
curve["y"] = {80,70,65,18} 
 
--offset=2 
--log(linear_by_table(20,curve,offset)) 
log(linear_by_table(-15,curve))
  
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 14 
	Threads: 1 
	Joined: Sep 2024
	
 Reputation: 
 0
	 
 
	
		
		
		16.01.2025, 11:42 
(This post was last modified: 16.01.2025, 11:43 by jerryhenke.
 Edit Reason: added code
)
		
	 
	
		 (04.12.2018, 13:45)merel Wrote:  Hello. 
 
You can try this: 
 
Code: function linear_by_table(input,curve,offset) 
local FDY = offset or 0  
    fk1= (curve["y"][1] - curve["y"][2]) / (curve["x"][1] - curve["x"][2]) 
    fk2= (curve["y"][2] - curve["y"][3]) / (curve["x"][2] - curve["x"][3]) 
    fk3= (curve["y"][3] - curve["y"][4]) / (curve["x"][3] - curve["x"][4]) 
 
    if input < curve["x"][1] then 
        out = curve["y"][1] + FDY; 
    elseif input >= curve["x"][1] and input < curve["x"][2] then     
        out = fk1 * (input - curve["x"][1]) + curve["y"][1] + FDY 
    elseif input >= curve["x"][2] and input < curve["x"][3] then 
        out = fk2 * (input - curve["x"][2]) + curve["y"][2] + FDY 
    elseif input >= curve["x"][3] and input < curve["x"][4] then     
        out = fk3 * (input - curve["x"][3]) + curve["y"][3] + FDY 
    else 
        out = curve["y"][4] + FDY 
    end 
  return out 
end 
 
curve = {} 
curve["x"] = {-20,-10,0,20} 
curve["y"] = {80,70,65,18} 
 
--offset=2 
--log(linear_by_table(20,curve,offset)) 
log(linear_by_table(-15,curve))
  Wow. Thanks! Used this today and made some small changes.
 
My code looks like this and runs nicely.
 
 Code: function linear_by_table(input, curve, offset) 
    local FDY = offset or 0 
    local n = #curve["x"] -- Number of points 
    if n ~= #curve["y"] then 
        error("x and y lists must have the same number of values") 
    end 
    local out 
    if input < curve["x"][1] then 
        out = curve["y"][1] + FDY 
    elseif input >= curve["x"][n] then 
        out = curve["y"][n] + FDY 
    else 
        for i = 1, n - 1 do 
            if input >= curve["x"][i] and input < curve["x"][i + 1] then 
                local fk = (curve["y"][i + 1] - curve["y"][i]) / (curve["x"][i + 1] - curve["x"][i]) 
                out = fk * (input - curve["x"][i]) + curve["y"][i] + FDY 
                break 
            end 
        end 
    end 
    return out 
end 
-- Define the curve for interpolation 
local curve = {x = {-20, -10, 0, 10, 20}, y = {42, 34, 32, 25, 15}} 
-- Adjust offset to shift the entire curve 
local offset = 0 
-- Get outdoor temperature from KNX address 0/3/0 
local outdoor_temp = grp.getvalue('0/3/0') 
-- Calculate the flow setpoint based on the outdoor temperature 
local flow_setpoint = linear_by_table(outdoor_temp, curve, offset) 
-- Write the calculated value to KNX address 5/5/0 
grp.write('5/5/0', flow_setpoint) 
-- Log the results 
log('Outdoor temperature: ' .. outdoor_temp .. ', Flow setpoint: ' .. flow_setpoint)
  
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 1807 
	Threads: 7 
	Joined: Jul 2015
	
 Reputation: 
 121
	 
 
	
	
		For the outdoor temp combined with a curve i usually use a 3 days average, this can simply be done by attaching a trend to your measurement object and use this small script. 
Code: require('trends') 
dateslastthreedays = {} 
dateslastthreedays['start'] = os.date('*t', os.time() - (86400 * 4)) 
dateslastthreedays['end'] = os.date('*t', os.time() - (86400 * 1)) 
threedaysaverage = trends.fetchone('OUTDOOR TEMP', dateslastthreedays)
  
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 14 
	Threads: 1 
	Joined: Sep 2024
	
 Reputation: 
 0
	 
 
	
		
		
		16.01.2025, 21:56 
(This post was last modified: 16.01.2025, 22:04 by jerryhenke.)
		
	 
	
		 (16.01.2025, 17:08)Erwin van der Zwart Wrote:  For the outdoor temp combined with a curve i usually use a 3 days average, this can simply be done by attaching a trend to your measurement object and use this small script. 
 
Code: require('trends') 
dateslastthreedays = {} 
dateslastthreedays['start'] = os.date('*t', os.time() - (86400 * 4)) 
dateslastthreedays['end'] = os.date('*t', os.time() - (86400 * 1)) 
threedaysaverage = trends.fetchone('OUTDOOR TEMP', dateslastthreedays)
  
The only trend I have right now is outdoor temperature with a 5-min resolution. 
I tried your script and can't really make it work. 
I get incorrect values. I would rather like to use a span of the last 9 hours average temperature or so, not from four days agou until yesterday which i read your script. 
I tried change 86400 * 4 to 86400 * 1 and the "end" to 86400 * 0, but that gives 0 as temperature. 
 
Any good suggestions?
 Quote:require('trends') 
 
-- Define time range for the timespan 
local lastninehours = {} 
lastninehours['start'] = os.date('*t', os.time() - (3600 * 9)) -- 9 hours back 
lastninehours['end'] = os.date('*t', os.time()) -- Current time 
 
-- Fetch the average temperature for the timespan 
local ninehoursaverage = trends.fetchone('Utetemp', lastninehours) 
 
-- Fetch the current temperature from KNX address 0/3/0 
local currenttemperature = grp.getvalue('0/3/0') -- Assumes grp.getvalue function is used 
 
if ninehoursaverage and currenttemperature then 
    -- Calculate the highest value between the average temperature and the current temperature 
    local highesttemperature = math.max(ninehoursaverage, currenttemperature) 
     
    -- Send the highest value to KNX address 5/5/20 
    grp.write('5/5/20', highesttemperature) 
     
    -- Log both the average temperature and the temperature sent 
    log("Average temperature for the last 9 hours: " .. tostring(ninehoursaverage)) 
    log("Temperature sent to 5/5/20: " .. tostring(highesttemperature)) 
else 
    log("Could not fetch the average temperature or the current temperature.") 
end 
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 1807 
	Threads: 7 
	Joined: Jul 2015
	
 Reputation: 
 121
	 
 
	
	
		You always fetch a full day, that is why my sample is using yesterday until 4 days back, so 3 full days.. 
From the knowledge base ( time values are ignored) :
 Code: dates - Lua table with two items - start and end, each item must contain year, month, day keys, time values (hours, minutes and seconds) are ignored
 
You can get today via:
 Code: require('trends') 
local today = {} 
today['start'] = os.date('*t', os.time())  
today['end'] = os.date('*t', os.time() + 86400) 
 
-- Fetch the average temperature for the timespan 
local todayaverage = trends.fetchone('Temperatuur Woonkamer', today) 
 
log(todayaverage)
   
To see the full data used just change  -> trends.fetchone into  -> trends.fetch, here you will see all samples of today
	  
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 8422 
	Threads: 45 
	Joined: Jun 2015
	
 Reputation: 
 481
	 
 
	
	
		KB doc needs updating. It's possible to fetch data for the given period if start/end is a not a table but a timestamp number. 
Fetch data for the last hour:
 Code: date = os.date('*t') -- current date as a table 
time = os.time(date, true) -- convert UTC timestamp 
 
-- fetch data for the last hour (3600 seconds) 
datarange = { 
  ['start'] = time - 3600, 
  ['end'] = time, 
} 
 
data = trends.fetch('trend name', datarange) 
log(data)
  
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 1807 
	Threads: 7 
	Joined: Jul 2015
	
 Reputation: 
 121
	 
 
	
	
		Great! This makes it so much easier to use in many cases (:
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 14 
	Threads: 1 
	Joined: Sep 2024
	
 Reputation: 
 0
	 
 
	
		
		
		17.01.2025, 10:24 
(This post was last modified: 17.01.2025, 10:26 by jerryhenke.)
		
	 
	
		 (17.01.2025, 08:18)admin Wrote:  KB doc needs updating. It's possible to fetch data for the given period if start/end is a not a table but a timestamp number. 
 
Fetch data for the last hour: 
Code: date = os.date('*t') -- current date as a table 
time = os.time(date, true) -- convert UTC timestamp 
 
-- fetch data for the last hour (3600 seconds) 
datarange = { 
  ['start'] = time - 3600, 
  ['end'] = time, 
} 
 
data = trends.fetch('trend name', datarange) 
log(data)
  
Amazing. Now it seems to work. 
 
I ended up with this script for a damped outdoor temperatur that i later use for my control of floor heating. 
Thougts?
 
Also - do I have to define the resolution of the trend log that I use? Now mine is 5 minutes, but I am also starting a 1 hour-resolution trend log of outside temperature. I imagine less work for LM to calculate the average if I have a table with less values? 
 Quote:require('trends') 
 
-- Function to calculate time range based on hours and days 
local function get_time_range(start_hours, start_days, end_hours, end_days) 
    local date = os.date('*t') -- current date and time as a table 
    local current_time = os.time(date, true) -- convert to UTC timestamp 
    local start_time = current_time - (3600 * start_hours + 86400 * start_days) -- calculate start time 
    local end_time = current_time - (3600 * end_hours + 86400 * end_days) -- calculate end time 
 
    return { 
        ['start'] = start_time, 
        ['end'] = end_time 
    } 
end 
 
-- Define time range (replace the number of hours and days with your values) 
local start_hours_back = 0 -- hours back from current time for start time 
local start_days_back = 1 -- days back from current time for start time 
local end_hours_back = 0 -- hours back from current time for end time 
local end_days_back = 0 -- days back from current time for end time 
local time_range = get_time_range(start_hours_back, start_days_back, end_hours_back, end_days_back) 
 
-- Specify resolution for 5-minute data (360 seconds) 
local resolution = 360 
 
-- Fetch average temperature for the time period with specified resolution 
local periodaverage = trends.fetchone('Utetemp', time_range, resolution) 
 
-- Fetch the current temperature from KNX address 0/3/0 
local currenttemperature = grp.getvalue('0/3/0') -- Assuming grp.getvalue function is used 
 
if periodaverage and currenttemperature then 
    -- Calculate the highest value between the average temperature and the current temperature 
    local highesttemperature = math.max(periodaverage, currenttemperature) 
 
    -- Send the highest value to KNX address 5/5/20 
    grp.write('5/5/20', highesttemperature) 
 
    -- Log both the average temperature and the temperature sent 
    log("Average temperature for selected period: " .. tostring(periodaverage)) 
    log("Temperature sent to 5/5/20: " .. tostring(highesttemperature)) 
    log("Current temperature at 0/3/0: " .. tostring(currenttemperature)) 
else 
    log("Could not fetch the average temperature or the current temperature.") 
end 
	 
	
	
	
		
	 
 
 
	 
 |