Search code examples
luaesp8266nodemcupanicesplorer

Error in code. Lua on NodeMCU


I have a motorized roller blind project. I am following this instructable: https://www.instructables.com/id/Motorized-WiFi-IKEA-Roller-Blind/ .

I am using the code in the instructable, but I suspect tha fault is in one of these codes:

config.lua

-- file : config.lua
local module = {}
module.SSID = {}
module.SSID["ssid"] = "password"

-- example for local MQTT
--module.MQHOST = "ohab.local"
--module.MQPORT = 1883
--module.MQID = node.chipid()
--module.MQUSR = ""
--module.MQPW = ""

-- example for cloud MQTT
module.MQHOST = "192.***.*.*"
module.MQPORT = 1883
module.MQID = node.chipid()
module.MQUSR = "username"
module.MQPW = "password"
module.MQTLS = 1 -- 0 = unsecured, 1 = TLS/SSL
module.ENDPOINT = "/house/masterbedroom/rollerblind/"
module.ID = "0"

--module.SUB = "set"
module.SUB = {[module.ENDPOINT .. module.ID .. "/set"]=0,[module.ENDPOINT .. "all"]=0}
module.POST = module.ENDPOINT .. module.ID .. "/status"
return module

wifi_setup

-- file: setup.lua
local module = {}
local function wifi_wait_ip()
    if wifi.sta.getip()== nil then
        print("IP unavailable, Waiting...")
    else
        tmr.stop(1)
        gpio.write(pin_led,1) --off
        print("\n================== ==================")
        print("ESP8266 mode is: " .. wifi.getmode())
        print("MAC address is: " .. wifi.ap.getmac())
        print("IP is "..wifi.sta.getip())
        print("====================================")
        mq.start()
    end
end

local function wifi_start(list_aps)
    if list_aps then
        gpio.write(pin_led,0) --on
        for key,value in pairs(list_aps) do
            if config.SSID and config.SSID[key] then
                wifi.setmode(wifi.STATION);
                wifi.sta.config(key,config.SSID[key])
                wifi.sta.connect()
                print("Connecting to " .. key .. " ...")
                --config.SSID = nil  -- can save memory
                tmr.alarm(1, 2500, 1, wifi_wait_ip)
            end
        end
    else
        print("Error getting AP list")
    end
end

function module.start()
  print("Configuring Wifi ...")
  wifi.setmode(wifi.STATION);
  wifi.sta.getap(wifi_start)
end
return module

Sadly I cant manage to go beyond step 4. After I have tried to download the code to the ESP8266 I only get this error:

PANIC: unprotected error in call to Lua API (wifi_setup.lua:25: bad argument #1 to 'config' (config table not found!))

screenshot of error from the ESPlorer program

I have only changed the stuff the instructable told me to change, and I have tried to look for faults myself but I cant find any... It's the first time I am using Lua, so this is totally new for me.

Hope somebody here can offer some help. Been stuck on this for days...

THIS PART OF THE PROBLEM IS SOLVED. CHECK COMMENTS FOR SOLUTION


Sadly when one problem is solved, a new one rises...

The chip is now successfully connecting to the wifi and mqtt service, but when I try to do the dry run by putting in the command 'step_move(1000,FWD,2)' nothing happens. The motor should rotate...

Also when I press the button I get a new panic error as follows:

PANIC: unprotected error in call to Lua API (button.lua:23: attempt to perform arithmetic on upvalue '?' (a nil value))

button.lua

--file button4.lua

do
  -- use pin 1 as the input pulse width counter
  local pin=5
  local debounce = 150 --ms
  local longpress = 2000 --ms
  local pulse1, pulse2, du, now, trig = 1, 0, 0, tmr.now, gpio.trig
  local prev_int_time, int_time, up_time = 0
  local cal_steps = 100000
  local cal_steps_dn = 0
  local cal_steps_up = 0
  local cal_state = 0 -- 0 = not calibration, 1 = calibrating down, 2 = calibrating up
  state = 0 -- state: 0 = up, 1 = transition, 2 = down
  gpio.mode(pin,gpio.INT)

  local function pin4cb(level)
    int_time = now() / 1000
    if ((int_time - prev_int_time) > debounce) then
      if (level == 0) then
        up_time = int_time
      else
        if((int_time - up_time) > longpress) then
          print("calibrating")
          cal_state = 1
          --cur_step = 100000
          step_move(cal_steps,FWD,2)
        else -- short press
          print("short", cal_state)
          if (cal_state == 2) then -- calibrated up (done)
            print("calibration done")
            state = 0 -- up
            cur_step = 0
            tot_steps = cal_steps - step_stepsleft
            print("cal_steps: " .. cal_steps)
            print("step_stepsleft: " .. step_stepsleft)
            print("tot_steps: " .. tot_steps)
            step_stop()
            pins_disable()
            cal_state = 0
            if file.open("cfg_tot_steps.lua", "w+") then
              file.write("tot_steps=" .. tot_steps .. '\n')
              file.close()
            end
          elseif (cal_state == 1) then -- calibrated dn (switch direction)
            print("calibration low point")
             print(cal_steps - step_stepsleft) 
            step_stop()
            step_move(cal_steps,REV,2)
            cal_state = 2
          elseif (cal_state == 0) then
            if (state == 0 and step_stepsleft == 0) then -- i am up, go dowm
              rollerblind.down()
--              state = 2
            elseif (state == 1) then -- i am moving, do nothing
              -- do nothing
            elseif (state == 2 and step_stepsleft == 0) then -- i am down, go up
              rollerblind.up()
--              state = 0
            end
         end
       end
      end
      --print (level)
      prev_int_time = int_time
    end
  end
      gpio.trig(pin, "both", pin4cb)
 end

Here is the code for the stepper.lua:

    -- stepper.lua
-- code from: http://www.esp8266.com/viewtopic.php?f=19&t=2326
-- simple stepper driver for controlling a stepper motor with a
-- l293d driver
-- nodemcu pins:  0  5  6  7
stepper_pins = {1,3,2,4} -- (A-)blue, (A+)pink, (B-)yellow, (B+)orange
--stepper_pins = {1,2,3,4}
-- half or full stepping
step_states4 = {
 {1,0,0,1},
 {1,1,0,0},
 {0,1,1,0},
 {0,0,1,1}
}
step_states8 = {
 {1,0,0,0},
 {1,1,0,0},
 {0,1,0,0},
 {0,1,1,0},
 {0,0,1,0},
 {0,0,1,1},
 {0,0,0,1},
 {1,0,0,1},
}
step_states = step_states4 -- choose stepping mode
step_numstates = 4 -- change to match number of rows in step_states
step_delay = 10 -- choose speed
step_state = 0 -- updated by step_take-function
step_direction = 1 -- choose step direction -1, 1
step_stepsleft = 0 -- number of steps to move, will de decremented
step_timerid = 4 -- which timer to use for the steps
status_timerid = 2 -- timer id for posing of status messages
-- setup pins
function pins_enable()
  for i = 1, 4, 1 do
    gpio.mode(stepper_pins[i],gpio.OUTPUT)
  end
end

function pins_disable()
--  for i = 1, 4, 1 do -- no power, all pins
  for i = 2, 4, 1 do -- no power, all pins except one (to keep it in place)
    gpio.mode(stepper_pins[i],gpio.INPUT)
  end
end
-- turn off all pins to let motor rest
function step_stopstate() 
  for i = 1, 4, 1 do
    gpio.write(stepper_pins[i], 0)
  end
end

-- make stepper take one step
function step_take()
  -- jump to the next state in the direction, wrap
  step_state = step_state + step_direction
  cur_step = cur_step + step_direction * FWD
      if step_state > step_numstates then
    step_state = 1;
  elseif step_state < 1 then
    step_state = step_numstates
  end
  -- write the current state to the pins
  pins_enable()
  for i = 1, 4, 1 do
    gpio.write(stepper_pins[i], step_states[step_state][i])
  end
  -- might take another step after step_delay
  step_stepsleft = step_stepsleft-1
  if step_stepsleft > 0 then
--  if cur_step > 0 and cur_step < tot_steps and step_stepsleft > 0 then
    tmr.alarm(step_timerid, 10, 0, step_take )
    --tmr.alarm(step_timerid, 10, 0, step_take )
  else
    step_stopstate()
    step_stop()
    pins_disable()
    mq.post_status()
    if file.open("cfg_cur_step.lua", "w+") then
      file.write("cur_step=" .. cur_step .. '\n')
      file.close()
    end
  end
end

-- public method to start moving number of 'int steps' in 'int direction'    
function step_move(steps, direction, delay)
  tmr.stop(step_timerid)
  step_stepsleft = steps
  step_direction = direction
  step_delay = delay
  step_take()
end

function step_go_to(step, delay)
  if step >= cur_step then
    steps = step - cur_step
    step_move(steps, FWD, delay)
  end
  if step <= cur_step then
    steps = cur_step - step
    step_move(steps, REV, delay)
  end
end

function percent_go_to(percent, delay)
  if(percent >= 0 and percent <= 100) then
    step_stop()
    tmr.register(status_timerid, 1000, tmr.ALARM_AUTO, function () mq.post_status() end)
    tmr.start(status_timerid)
    step = percent * tot_steps / 100
    step_go_to(step, delay)
  end
end

-- public method to cancel moving
function step_stop()
  tmr.stop(step_timerid)
  tmr.stop(status_timerid)
  step_stepsleft = 0
  step_stopstate()
end

Solution

  • ComicSansMS provided a great answer the essence of which is that you need to replace

    wifi.sta.config(key,config.SSID[key])
    

    with

    wifi.sta.config{ssid=key,pwd=config.SSID[key]}
    

    Thus a standalone example could be like this:

    --wifi.setmode(wifi.NULLMODE)
    
    config = {}
    config.SSID = {}
    config.SSID["ssid"] = "password"
    
    function wifi_wait_ip()
      if wifi.sta.getip() == nil then
        print("IP unavailable, Waiting...")
      else
        tmr.stop(1)
        print("\n====================================")
        print("ESP8266 mode is: " .. wifi.getmode())
        print("MAC address is: " .. wifi.ap.getmac())
        print("IP is " .. wifi.sta.getip())
        print("====================================")
      end
    end
    
    function wifi_start(list_aps)
      if list_aps then
        for key, value in pairs(list_aps) do
          if config.SSID and config.SSID[key] then
            wifi.setmode(wifi.STATION);
            wifi.sta.config{ssid=key, pwd=config.SSID[key]}
            -- wifi.sta.connect() not needed as config() uses auto-connect=true by default
            print("Connecting to " .. key .. " ...")
            tmr.alarm(1, 2500, 1, wifi_wait_ip)
          end
        end
      else
        print("Error getting AP list")
      end
    end
    
    function start()
      print("Configuring Wifi ...")
      wifi.setmode(wifi.STATION)
      wifi.sta.getap(wifi_start)
    end
    
    start()