analog_pin = 0 t = require("DS1820") num_readings = 8 readings = {} read_index = 1 total = 0 timing = 6000 ds_pin = 1 pin_ten = 2 pin_fan = 6 pin_led_g = 7 pin_led_r = 5 adc_min = 0 adc_max = 1023 steps = {4, 8, 12, 16, 20, 24, 28} current_t = 16 hysteresis = 1 ten_on_time = 0 ten_off_time = 0 ten_was_active = false gpio.mode(pin_ten, gpio.OUTPUT) gpio.mode(pin_fan, gpio.OUTPUT) gpio.mode(pin_led_g, gpio.OUTPUT) gpio.mode(pin_led_r, gpio.OUTPUT) gpio.write(pin_ten, gpio.HIGH) gpio.write(pin_fan, gpio.HIGH) gpio.write(pin_led_g, gpio.LOW) gpio.write(pin_led_r, gpio.LOW) if adc.force_init_mode(adc.INIT_ADC) then node.restart() end for i = 1, num_readings do readings[i] = 0 end results = {} function read_smoothed_adc() total = total - readings[read_index] local raw = adc.read(analog_pin) readings[read_index] = raw total = total + raw read_index = read_index + 1 if read_index > num_readings then read_index = 1 end return total / num_readings end function control_logic(avg_temp) local time_now = tmr.time() local temp_ok = (avg_temp >= (current_t - hysteresis)) and (avg_temp <= (current_t + hysteresis)) if temp_ok then gpio.write(pin_led_g, gpio.HIGH) gpio.write(pin_led_r, gpio.LOW) else gpio.write(pin_led_g, gpio.LOW) gpio.write(pin_led_r, gpio.HIGH) end if avg_temp < (current_t - hysteresis) then if gpio.read(pin_ten) == gpio.HIGH then gpio.write(pin_ten, gpio.LOW) ten_on_time = time_now ten_was_active = true end if ten_was_active and ten_on_time > 0 and (time_now - ten_on_time >= 300) then if gpio.read(pin_fan) == gpio.HIGH then gpio.write(pin_fan, gpio.LOW) end else gpio.write(pin_fan, gpio.HIGH) end elseif avg_temp > (current_t + hysteresis) then gpio.write(pin_ten, gpio.HIGH) ten_was_active = false ten_on_time = 0 if gpio.read(pin_fan) == gpio.HIGH then gpio.write(pin_fan, gpio.LOW) end else if gpio.read(pin_ten) == gpio.LOW then gpio.write(pin_ten, gpio.HIGH) ten_off_time = time_now end if ten_was_active and ten_off_time > 0 then if (time_now - ten_off_time >= 300) then gpio.write(pin_fan, gpio.HIGH) ten_was_active = false ten_on_time = 0 ten_off_time = 0 end else gpio.write(pin_fan, gpio.HIGH) end end local ten_state = gpio.read(pin_ten) == gpio.LOW and 1 or 0 local fan_state = gpio.read(pin_fan) == gpio.LOW and 1 or 0 print(string.format("T_cur: %2d C | T_set: %2d C | TEN: %d | FAN: %d | Act: %s", avg_temp, current_t, ten_state, fan_state, tostring(ten_was_active))) end function readout(temp) local count = 0 local sum = 0 for addr, t_val in pairs(temp) do local short_id = string.format('%02X', addr:byte(8)) local t_ceil = t_val if t_val > 1000 then t_ceil = t_val / 10000 end results[short_id] = t_ceil print("Sensor " .. short_id .. ": " .. t_ceil .. " C") sum = sum + t_ceil count = count + 1 end if count > 0 then control_logic(sum / count) else print("No sensors found") end end function read_sensors() t:read_temp(readout, ds_pin, t.C) end function start_web_server() wifi.setmode(wifi.SOFTAP) local cfg = {} cfg.ssid = "Thermostat-WiFi" wifi.ap.config(cfg) srv = net.createServer(net.TCP) srv:listen(80, function(conn) conn:on("receive", function(sck, payload) local response = {"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n"} table.insert(response, "
") table.insert(response, "Target Temp: " .. current_t .. " C
Tank [ID: " .. id .. "]: " .. temp .. " C
") end table.insert(response, "") local function send_chunk(sk) if #response > 0 then sk:send(table.remove(response, 1)) else sk:close() end end sck:on("sent", send_chunk) send_chunk(sck) end) end) print("HTTP Server started on 192.168.4.1") end tmr.create():alarm(2000, tmr.ALARM_SINGLE, function() collectgarbage() start_web_server() sensortimer = tmr.create() sensortimer:register(timing, tmr.ALARM_AUTO, read_sensors) sensortimer:start() adctimer = tmr.create() adctimer:register(300, tmr.ALARM_AUTO, function() local avg_raw = read_smoothed_adc() if avg_raw < adc_min then avg_raw = adc_min end if avg_raw > adc_max then avg_raw = adc_max end local step_index = 1 + ((avg_raw - adc_min) * (#steps - 1)) / (adc_max - adc_min) if step_index > #steps then step_index = #steps end if step_index < 1 then step_index = 1 end current_t = steps[step_index] end) adctimer:start() end)