0

I developed a simple app in MIT APP Inventor that controls a heat pump water heater.

The app sends a different string for each button pressed and the NodeMcu verifies which button was pressed, as you can see in the code below.

srv=net.createServer(net.TCP)
srv:listen(80,function(conn)

conn:on("receive", function(client,request)
    local buf = ""
    local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP")
    if(method == nil)then 
        _, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP")
    end
    local _GET = {}
    if (vars ~= nil)then
        for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do
            _GET[k] = v
        end
    end
    local _on,_off = "",""

    if(_GET.pin == "ip")then
        local ip=wifi.sta.getip()
        local ler_ip=string.sub(ip,1,13)
        dofile("novolcd.lua").cls()
        dofile("novolcd.lua").lcdprint("IP="..ler_ip)
     elseif(_GET.pin == "05a60")then
        sp_temperaturas[5]=60

     elseif(_GET.pin == "06a60")then
        sp_temperaturas[6]=60

     elseif(_GET.pin == "Ferias")then
        dofile("novolcd.lua").cls()
        dofile("novolcd.lua").lcdprint("  Modo ferias   ")
        modo_ferias()

     elseif(_GET.pin == "Parar2")then
       dofile("novolcd.lua").cls()
        dofile("novolcd.lua").lcdprint("  Parar")
     end

end)
conn:on("sent", function (c) c:close() end)
  end)

And when the button "Ferias" is pressed the system starts the heating process by calling the function modo_ferias().

     function aquecer()

        local kp=100/10
        local ki=5
        local kd=5
        local tempo_on=0
        local tempo_off=0
        i=0
        local duty=0            
        erro=sp_temp-t_atual
        soma_erro = soma_erro + erro/5;
        dif_erro = (erro - erro_ant)/5;
        erro_ant = erro;
        print(erro.."          "..soma_erro.."    "..dif_erro)
        duty= kp * erro + soma_erro / ki + dif_erro * kd 
        print(duty)

        tempo_on= duty *50   
        if (tempo_on > 5000) then
            tempo_on = 5000
        end

        tempo_off = 5000 - tempo_on

        repeat
            i = i + 1
            tmr.delay(1000)
        until (i >= tempo_off)               

        gpio.write(8, gpio.HIGH)

        repeat
            i = i + 1      
            tmr.delay(1000)       
        until (i == 5000)

        gpio.mode(8, gpio.INPUT)

    end

    function modo_ferias()

        repeat            
            sair_ferias=0
            pressao()
            if (pressao_psi <=3)
                sair_ferias=1
            end 
            t_atual=ler_temperatura()
            local int = string.format("%d", t_atual )    -- parte inteira
            local dec = string.format("%.1d", t_atual % 10000)  -- parte decimal com uma casa
            t_display = int .. "." .. dec
            rtc()
            dofile("novolcd.lua").cls()
            dofile("novolcd.lua").lcdprint("Temp="..t_display.."  ST="..sp_temp..data_horas)
            sp_temp=40
           local horas_ferias=hour
           if(horas_ferias==0 or horas_ferias==1 or horas_ferias==2 or horas_ferias==3 or horas_ferias==4 or horas_ferias==5 or horas_ferias==6) then
             sp_temp=70
           end 
            if (sp_temp>t_atual) then
                aquecer()

            end  
        until (sair_ferias==1)    
    end

And here is where my problem appears. If I press a button form the app after the "Ferias" button been pressed, the NodeMcu won't know it because the program is in the heating functions and not verifying if the app sended any instruction.

Is there any way to listen the app commands and to do the heating process at the same time?

  • The issue is that your function `aquecer()` never relinquishes control. `tmr.delay()` is a busy loop, nothing else can run simultaneously (like your TCP server). You need to rewrite your code to work using events with only one main loop. For example, have your TCP handler set a global flag to indicate a button was pressed. That global flag is read by your main function as it performs the main loop. – ktb Aug 22 '17 at 03:06

1 Answers1

0

There are a few things

Global state

because the program is in the heating functions and not verifying if the app sended any instruction

If the commands triggered by pressing the various buttons can not run independently from each other then you need some form of global state to make sure they don't interfere.

Busy loop

repeat
    i = i + 1
    tmr.delay(1000)
until (i == 5000)

This is a no-go with NodeMCU as it's essentially a stop-the-world busy loop. Besides, tmr.delay is scheduled to be removed because it's abused so often.

Task posting

node.task.post is a possible solution to scheduling tasks for execution "in the near future". You could use this to post task from the on-receive callback rather executing them synchronously.

Marcel Stör
  • 22,695
  • 19
  • 92
  • 198
  • First of all thank you for helping. To be sincere I tried to understand the noed.task.post solution but without exit. I don't understand how can I define the server as HIGH priority and how could I correlate both the listening part and the heating part. Could't it work to listening while on the loop i = i + 1 tmr.delay(1000) until (i == 5000) For example put the coon here? I also tried to use the tmr.alarm() to resolve the problem but the initial problem occurs. There isn't a way to use a timer to go back to the server for like 4 seconds and then come back to heating? – Gonçalo Mendes Aug 23 '17 at 13:37