local variable referenced before assignment

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
bellad
Posts: 83
Joined: Tue May 14, 2019 1:47 pm

local variable referenced before assignment

Post by bellad » Wed Feb 05, 2020 9:29 am

Hello ,
i have changed , like i can't with esp8266 , i try with esp32 in multi thread
i have declared 'ab=0' in the beginning
but
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "chauf33.py", line 250, in <module>
File "chauf33.py", line 130, in apl1
NameError: local variable referenced before assignment
ligne 130 > if ab != 3:
i not understand , the variable is not global in the beginnig ??

Code: Select all

import machine
import utime
from bme280 import *
import _thread as th


g=0
rel= machine.Pin(12, machine.Pin.OUT)
led = machine.Pin(13, machine.Pin.OUT)
try:
  import usocket as socket
except:
  import socket
try:
  import ustruct as struct
except:
  import struct

# (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60
NTP_DELTA = 3155673600
mo=('Travail','Presence','absence','exception')
jr=('Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi','Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi','Dimanche')
host = "192.168.1.79" # serveur ntp interne
hosts="0.fr.pool.ntp.org" # serveur ntp internet
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)
ex=''
h1='#0F3376'
ab=0
m=0

mm=0
ind=0
rep='t'


  

  
  
    
def temp():
  l=open('te.txt','r')
  li=l.read()
  bmp=BME280(i2c=i2c, address=BME280_I2CADDR)
  ts=bmp.raw_values
  temper=ts[0]
  return round(temper+float(li),2)
  
def web_page():
  tempera=str(temp())+' / '+str(tempf)
  ddt=jr[u[6]]+' '+str(u[3])+' h '+str(u[4])
  
  
  
  
  html = """<html><head> <title>Chambre parentale</title> <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,"> <style>html{font-family: Helvetica; display:inline-block; margin: 0px auto; text-align: center;}
  h1{color: """+h1+"""; padding: 2vh;}p{font-size: 1.5rem;}.button1{display: inline-block; background-color: #ed7a0e; border: double; 
  border-radius: 4px; color: white; padding: 3px 5px; text-decoration: none; font-size: 20px; margin: 2px; cursor: pointer;}
  .button2{display: inline-block; background-color: #0c2f5c; border: double; border-radius: 4px; color: white; padding: 3px 5px ;
  text-decoration: none; font-size: 20px; margin: 2px; cursor: pointer;}

  .button3{display: inline-block; background-color: #0c5c13; border: double; border-radius: 4px; color: white; padding: 3px 5px ;
  text-decoration: none; font-size: 20px; margin: 2px; cursor: pointer;}</style></head><body> <h1>Chambre parentale</h1>
  <p>"""+ddt+"""</p> 
  <p>Temperature: <strong>""" + tempera + """</strong><p>Mode: <strong>""" + mo[ab] + """</strong></p><p><a href="/?led=on"><button class="button1">Travail</button></a>
  <a href="/?led=off"><button class="button2">Presence</button></a><a href="/?led2=on"><button class="button3">Absence</button></a><div>
  <p <h1>____________________________</h1></p>
  <p <h1><B>Demande exceptionnelle</B></h1></p>
  <form action=”” method=”POST”>
      <p align="center" style="margin-bottom: 0cm; line-height: 100%">
    <input type="text" id="name1" name="name1" required
       minlength="2" maxlength="2" size="3" value=''>
	   <label for="contactChoice1"> Degres_    </label>
	<input type="text" id="name2" name="name2" required
       minlength="1" maxlength="2" size="2" value=''> 
       <label for="contactChoice1">Heure(s) </label>
      <p align="center" style="margin-bottom: 0cm; line-height: 100%"><button type="submit">Enregistrer</button><p/>
      <p>"""+ex+"""</p> 
   </form>	  
   </div></p></body></html>"""
  return html

	  
def timep():
  try:
    NTP_QUERY = bytearray(48)
    NTP_QUERY[0] = 0x1b
    addr = socket.getaddrinfo(host, 123)[0][-1]
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.settimeout(1)
    res = s.sendto(NTP_QUERY, addr)
    msg = s.recv(48)
    s.close()

    val = struct.unpack("!I", msg[40:44])[0]
    return val - NTP_DELTA
  except:
    
    try:
      NTP_QUERY = bytearray(48)
      NTP_QUERY[0] = 0x1b
      addr = socket.getaddrinfo(hosts, 123)[0][-1]
      s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
      s.settimeout(1)
      res = s.sendto(NTP_QUERY, addr)
      msg = s.recv(48)
      s.close()
      val = struct.unpack("!I", msg[40:44])[0]
      return val - NTP_DELTA
    except:
      pass

def settimep():
  t = timep()
  tm = utime.localtime(t)
  tm = tm[0:3] + (0,) + tm[3:6] + (0,)
  machine.RTC().datetime(tm)


def apl1():
  while True :
    dat=[]
    aa=0
    settimep()
    u=utime.localtime()
    if ab != 3:
      ind=0
      ex=''
  
    if ab==0 or ab==1: # si presence ou travail
      with open(rep+str(u[6])+'.txt') as file: # lecture fichier suivant le jour ( 0 = lundi )
        for line in file.read().strip().split("\r"):
          aa=aa+1
          liste = [int(c) for c in line.strip().split(",")]
          dat.append(liste)
      ti=(u[3]*60)+(u[4]) # actuel heure*60 + minutes 
    #tb=(u[3]*60)+(u[4]+2) # actuel heure*60 + minutes +2
      for i in range(aa):

		    ta=(dat[i][0]*60)+dat[i][1] # heure*60 + minutes ( fichier du jour )
		    if ti >= ta: # si heure du actuel est superieur ou egale heure du fichier
		      tempf=float(dat[i][2]) # temperature demandee
  
    if ab==2: # si absence

      tempf=16
	 
    if ab==3: # si exception
      if ind == 0:
        hac=u[3]*60
        mac=u[4]
        ma=str(int(float(mac)))
        ht=hac+mac
        ta=int(heu)*60 # heure*60 ( fichier d exception )
        tempf=float(deg) # temperature demandee		  
        ind = 1
        ja= u[6] # garde jour actuel
        tah=int(ta/1440)
        if tah !=0 :
          
          j = tah # nombre de jours
          jh=int(((ta-(1440*j))+ht)/60) # reste de temps - nombre de jours
          j=j+ja
        else:
          jh=int(heu) +(hac/60) #nombres d heures
          j=ja # jour actuel 
        
        ex= 'se termine '+jr[j]+' '+str(int(jh))+' h '+ ma
      
      if j == u[6] and jh == u[3] and mac == u[4]:
        ind=0
        if av=='t':
          ab=0
        if av=='p':
          ab=1
        if av=='a':
          ab=2  
        rep=av
      
	  
   
   
	
    tem=float(temp())
  
    if tem < (tempf - 0.25):
      led.value(1)
      rel.value(1)
      g=1
      print('allumer')
      h1='#E12A1E'
	   
    if tem < (tempf +0.25) and g==1:
	    pass
    else:
      led.value(0)
      rel.value(0)
      g=0
      print('eteint')
      h1='#0F3376'
    
def apl2():
  while True:
    
    conn, addr = s.accept()
    request = conn.recv(1024)

    request = str(request)
    na=request.find('?')
    led_on = request.find('/?led=on')
    led_off = request.find('/?led=off')
    led2_on = request.find('/?led2=on')
  
    if request[na+1:na+6]=='name1' :
      deg=request[na+7:na+9]
      heu=request[na+16:na+18]
    
      ab=3
      av=rep
      rep='e'
    
    if led_on == 6:
      rep='t'
      ab=0
    
   
    if led_off == 6:
      rep='p'
      ab=1
    
    
    if led2_on == 6:
      rep='a'
      ab=2
    
    
   
  
    response = web_page()
    conn.send('HTTP/1.1 200 OK\n')
    conn.send('Content-Type: text/html\n')
    conn.send('Connection: close\n\n')
    conn.sendall(response)
    conn.close()
  
th.start_new_thread(apl1())
th.start_new_thread(apl2())




User avatar
jimmo
Posts: 1835
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: local variable referenced before assignment

Post by jimmo » Wed Feb 05, 2020 9:53 am

The way variable scoping works in Python is a bit subtle.

What's going on here is that the function assigns to "ab" (doesn't matter where in the function, as long as there's a line somewhere that assigns to it). Therefore, ab is a local variable for that function.

It doesn't matter that you also have a global variable called "ab". To solve this you need to use the "global" keyword to tell Python that you want to use the global variable rather than the local one.

Consider the this simplified example:

Code: Select all

a = 0

def foo():
  if a == 0:
     a = 1


Inside foo, because there's an assignment to "a", it considers "a" to be a local variable, which is referenced before it's assigned.

To tell Python to use the global "a" instead:

Code: Select all

a = 0

def foo():
  global a
  if a == 0:
     a = 1

User avatar
jimmo
Posts: 1835
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: local variable referenced before assignment

Post by jimmo » Wed Feb 05, 2020 9:54 am

Hopefully that makes sense, but if you do a search for "global keyword python" there are lots of tutorials on this topic.

bellad
Posts: 83
Joined: Tue May 14, 2019 1:47 pm

Re: local variable referenced before assignment

Post by bellad » Wed Feb 05, 2020 10:07 am

ok , thank you , i test , but , it is necessary to declare global in each ' def() ' of thread ?

User avatar
jimmo
Posts: 1835
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: local variable referenced before assignment

Post by jimmo » Wed Feb 05, 2020 10:25 am

It's necessary in any function where you also assign to the variable.

Threads are unrelated here as they just invoke the function.

fstengel
Posts: 55
Joined: Tue Apr 17, 2018 4:37 pm

Re: local variable referenced before assignment

Post by fstengel » Wed Feb 05, 2020 2:35 pm

Another way to globally access data without having to resort to local/global is by using objects.

Code: Select all

class AnObject:
    def __init__(self):
        self.data = 0
    
    def set(self, o):
        self.data = o
    
    def get(self):
       return self.data

ob = AnObject()

def test1():
    ob.set(32)

def test2():
    if ob.get()==32:
        print("Test 1 done")
    else:
        print("Test1 not done")

test2() # "Test 1 not done"
test1()
test2() # "Test 1 done"
ob is declared globally. One does not need to use global to access the object since one only uses it via its methods.

bellad
Posts: 83
Joined: Tue May 14, 2019 1:47 pm

Re: local variable referenced before assignment

Post by bellad » Thu Feb 06, 2020 9:07 am

ok , thank you ,
but , I am new in python and do not know 'thread'
can you look my code and tell me why the apl1 work and apl2 no work ?
apl1 = thermostat
apl2 = apli web for changed parameter of apl1

i tried all alone apl1 , but when start , i cannot do other
i have not " >>>"

I took an example from " ESP32 MicroPython Basic Multi-Tasking" on youtube
thank

User avatar
jimmo
Posts: 1835
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: local variable referenced before assignment

Post by jimmo » Thu Feb 06, 2020 9:36 am

Code: Select all

th.start_new_thread(apl1())
th.start_new_thread(apl2())
should be

Code: Select all

th.start_new_thread(apl1)
th.start_new_thread(apl2)
When you start a thread you tell it which function to use for that thread. Your code instead invokes the function, and passes the result of that to the start_new_thread function.

bellad
Posts: 83
Joined: Tue May 14, 2019 1:47 pm

Re: local variable referenced before assignment

Post by bellad » Thu Feb 06, 2020 9:53 am

but , i try only with apl1 , and when start with ' th.start_new_thread(apl1) '
TypeError: function missing 1 required positional arguments

ok , i see , "th.start_new_thread(apl1,())"

Post Reply