LogicMachine Forum
Thermostat PI - Printable Version

+- LogicMachine Forum (https://forum.logicmachine.net)
+-- Forum: LogicMachine eco-system (https://forum.logicmachine.net/forumdisplay.php?fid=1)
+--- Forum: Scripting (https://forum.logicmachine.net/forumdisplay.php?fid=8)
+--- Thread: Thermostat PI (/showthread.php?tid=3572)



Thermostat PI - XSPA2474KW - 21.09.2021

Hello,

is it possible to create a thermostat PI (e.g. MTN6212-04XX) with Wiser?
I don't mean to have an MTN6212-04XX in the installation and just to visualize through Wiser.

In fact, I need to replace the MTN6212-04XX with a script.

Thanks for your help!


RE: Thermostat PI - admin - 22.09.2021

This might be helpful: https://openrb.com/example-pid-thermostat-with-lm2/


RE: Thermostat PI - XSPA2474KW - 22.09.2021

In this link mentions that: There is a PID function already added by default in Logic Machine -> Scripts -> Tools menu.

I have Wiser and not Logic Machine and there isn't by default in Wiser.


RE: Thermostat PI - admin - 22.09.2021

The example is somewhat outdated. You need to create a user library named pid and copy the code there.
Then load the library in your resident script:
Code:
-- init pid algorithm if not p then   require('user.pid')   p = PID:init({     current = '1/1/1',     setpoint = '1/1/2',     output = '1/1/3'   }) end -- run algorithm p:run()



RE: Thermostat PI - XSPA2474KW - 22.09.2021

I will check it.

Thanks for the help.

Appreciated.


RE: Thermostat PI - XSPA2474KW - 24.09.2021

Can you please tell me what should I write to the residential script?

Thanks in advance.


RE: Thermostat PI - admin - 24.09.2021

See my previous post. The code there is for the resident script. Set the script sleep interval to at least 10 seconds or more. This controls how often the algorithm runs. Change group addresses as needed.


RE: Thermostat PI - XSPA2474KW - 19.10.2023

Hello

I have added in residential the following:
Code:
-- init pid algorithm if not p then   p = PID:init({     current = '32/2/16',     setpoint = '32/2/17',     output = '32/2/18'   }) end -- run algorithm p:run()

and in the user library the following

Code:
PID = {   -- default params   defaults = {     -- invert algorithm, used for cooling     inverted = false,     -- minimum output value     min = 0,     -- maximum output value     max = 100,     -- proportional gain     kp = 1,     -- integral gain     ki = 1,     -- derivative gain     kd = 1,   } } -- PID init, returns new PID object function PID:init(params)   local n = setmetatable({}, { __index = PID })   local k, v   -- set user parameters   n.params = params   -- copy parameters that are set by user   for k, v in pairs(PID.defaults) do     if n.params[ k ] == nil then       n.params[ k ] = v     end   end   -- reverse gains in inverted mode   if n.params.inverted then     n.params.kp = -n.params.kp     n.params.ki = -n.params.ki     n.params.kd = -n.params.kd   end   return n end -- resets algorithm on init or a switch back from manual mode function PID:reset()   -- previous value   self.previous = grp.getvalue(self.params.current)   -- reset iterm   self.iterm = 0   -- last running time   self.lasttime = os.time()   -- clamp iterm   self:clampiterm() end -- clamps iterm value function PID:clampiterm()   self.iterm = math.max(self.iterm, self.params.min)   self.iterm = math.min(self.iterm, self.params.max) end -- clamp and set new output value function PID:setoutput()   local t, object, value   self.output = math.max(self.output, self.params.min)   self.output = math.min(self.output, self.params.max)   value = math.floor(self.output)   local t = type(self.params.output)   -- write to output if object is set   if t == 'string' or t == 'table' then     if t == 'string' then       self.params.output = { self.params.output }     end     for _, output in ipairs(self.params.output) do       grp.write(output, value, dt.scale)     end   end end -- algorithm step, returns nil when disabled or no action is required, output value otherwise function PID:run()   local result   -- get manual mode status   local manual = self.params.manual and grp.getvalue(self.params.manual) or false   -- in manual mode, do nothing   if manual then     self.running = false   -- not in manual, check if reset is required after switching on   elseif not self.running then     self:reset()     self.running = true   end   -- compute new value if not in manual mode   if self.running then     -- get time between previous and current call     local now = os.time()     self.deltatime = now - self.lasttime     self.lasttime = now     -- run if previous call was at least 1 second ago     if self.deltatime > 0 then       result = self:compute()     end   end   return result end -- computes new output value function PID:compute()   local current, setpoint, deltasc, deltain, output   -- get input values   current = grp.getvalue(self.params.current)   setpoint = grp.getvalue(self.params.setpoint)   -- delta between setpoint and current   deltasc = setpoint - current   -- calculate new iterm   self.iterm = self.iterm + self.params.ki * self.deltatime * deltasc   self:clampiterm()   -- delta between current and previous value   deltain = current - self.previous   -- calculate output value   self.output = self.params.kp * deltasc + self.iterm   self.output = self.output - self.params.kd / self.deltatime * deltain   -- write to output   self:setoutput()   -- save previous value   self.previous = current   return self.output end

but is not working.
I have also this error below in the "error log" window

User library PID:133: attempt to perform arithmetic on field 'previous' (a nil value)
stack traceback:
User library PID:133: in function 'compute'
User library PID:110: in function 'run'


RE: Thermostat PI - admin - 20.10.2023

Check that 32/2/16 exists and has correct data type. Try restarting the script by performing disable/enable.