Created
December 19, 2010 13:15
-
-
Save pklaus/747320 to your computer and use it in GitHub Desktop.
Connecting to AVR NET-IO with python with a graphical user interface – http://www.mikrocontroller.net/topic/180211
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
#-*- coding:utf8 -*- | |
#======================================================= | |
# Connecting to AVR NET-IO with python | |
# with a graphical user interface | |
#======================================================= | |
# Funktionen: | |
#+ Grafische Benutzerschnittstelle für AVR NET-IO "out of the box" | |
#+ Auslesen und Anzeige aller verfügbaren Eingänge und Schalten der Ausgänge mit Schaltflächen | |
#+ Zugriff über LAN (mit Telnet) | |
#+ Logging aller Werte mit Timestamp in Logfile, kann mit Schaltfläche gestartet und gestoppt werden | |
#+ Option: Logfile zum Anhängen geöffnet lassen / bei jedem Loggen neu öffnen | |
#TODO: Diese Software ist noch ziemlich ausbaufähig: | |
#- Anzeige von Firmwareversion und Verbindungsdaten (inkl. Port und MAC) | |
#- Logfile-Optionen: Bei jedem Log-Start neue Datei beginnen mit Timestamp/Nummerierung / Überschreiben (Warnen) / Fortsetzen | |
#- Preprend file info as comments at beginning of logfile if newly started | |
#- Button "Logfile schließen und neu beginnen" (mit neuem Dateinamen/oder nicht, je nach Überschreibmodus) | |
#- Festwert-Buttons für Abfrageintervall | |
#- Abfrageintervall genauer machen (time.time()-Abfrage zum Auf-Feste-Sekunden-Legen, gemessene Korrektur (s.u.), Zeitgeber... | |
#- count errors | |
#- Different interface size: small, normal | |
#- class version (enable controlling several devices) | |
#- color selectors | |
#- .rc file for saving configuration | |
#- Lineare und andere Transformationsfunktionen für ADC-Werte | |
#- Transport: Seriell, Telnet, TCP/IP, I2C, CAN, USB, Andere, ... | |
#- Sensorprotokolle: AVR NET-IO, Ethersex, Voltmeter (z.B. McVoice M-980T TRUE REMS MULTIMETER) | |
#- Webserver integrieren, um Werte anliefern oder die Software fernsteuern zu können | |
#- Anzeige der Werte als laufend aktualisierte Kurve. | |
#- Anzeige der geloggten Werte aus der Logdatei. | |
#- Skalierungsfunktionen, Auto-Skalierung anhand der aufgetretenen Werte. | |
#- XY-Anzeige (z.B. Temperatur über Licht), für Kennlinienschreiber o.ä. | |
#- Kurven als Grafik speichern. | |
#- Eigene Bezeichnungen für Ein- und Ausgänge definierbar machen | |
#- Andere grafische Widgets: Digitalanzeige, Analoganzeige usw. | |
#- Anwendungsbezogene Spezial-Widgets, z.B. Tür-Reedsensor => Türsymbol offen/geschlossen | |
#- Widgets anzeigen oder weglassen, anders anordnen, Auswahl unterschiedlicher Widgets | |
#- Fehlerbehandlung bei Verbindungsausfall | |
#- Fehlerbehandlung bei Logfile-Problemen | |
#- Umstellung der Netzwerkparameter auf eigene Wunschwerte | |
#- Bedienung mehrerer Boards | |
#- Weitere (alle) Funktionen der Pollin-Software nachbilden | |
#- Umdefinieren der Portfunktionen (dann ist es nicht mehr der AVR NET-IO "out of the box" und benötigt eine andere Firmware) | |
import time | |
import telnetlib | |
import Tkinter | |
#======================================================= | |
#AVR NET-I/O Default Parameters: | |
#IP = 192.168.0.90 | |
#NETMASK = 255.255.255.0 | |
#GATEWAY = 192.168.0.254 | |
#TELNET PORT = 50290 | |
#Commands: | |
# GETPORT x | |
# GETADC x | |
# SETPORT x.y | |
# GETSTATUS | |
# GETIP | |
# SETIP x.x.x.x | |
# GETMASK | |
# SETMAST x.x.x.x | |
# GETGW | |
# SETGW x.x.x.x | |
# INITLCD | |
# WRITELCD x.y | |
# CLEARLCD x | |
# VERSION | |
# RESET | |
#Default network parameters | |
telnethost = '192.168.0.90' | |
telnetport = 50290 | |
outfilename = 'avrnetio.log' | |
Standard_Interval = 100 #in 1/100 seconds | |
#Set this to False if you want to reduce disk access | |
#Set this to True if you watch the output visually with "tail -f" or if you want to save avery query immediately | |
Logfile_open_close_for_each_entry = True | |
#======================================================= | |
# Connecting to device / initializing: | |
print 'Connecting to AVR NET-IO with telnet at IP %s on port %d' % (telnethost, telnetport) | |
#Connect on telnet port | |
netio = telnetlib.Telnet(telnethost, telnetport) | |
#send command and get results | |
def sg(netio, cmd): | |
netio.write(cmd + '\n') | |
return netio.read_until('\n').strip('\r\n') | |
#get version | |
def version(netio): | |
print 'Version info:' | |
print sg(netio,'version') | |
print netio.read_until('\n').strip('\r\n') | |
print netio.read_until('\n').strip('\r\n') | |
version(netio) | |
#get ipparams - but they are known when you can connect with telnet. | |
def ipparams(netio): | |
print 'IP parameters:' | |
print 'IP: ', sg(netio,'getip') | |
print 'Netmask:', sg(netio,'getmask') | |
print 'Gateway:', sg(netio,'getgw') | |
ipparams(netio) | |
#Get values of all ADCs and Status | |
def adcs(netio): | |
for i in [1,2,3,4]: | |
print 'ADC' + str(i) + ': ' + sg(netio,'getadc ' + str(i)).rjust(4) + ' -', | |
print sg(netio,'getstatus') | |
#Get value of specific ADC | |
def adc(netio,i): | |
return int(sg(netio,'getadc ' + str(i))) | |
print 'Blinking outputs...' | |
#Some blinking of outputs, for fun | |
for i in range(1): # Set higher value for longer blinkery | |
sg(netio,'setport 1.1') | |
time.sleep(0.1) | |
sg(netio,'setport 1.0') | |
sg(netio,'setport 2.1') | |
time.sleep(0.1) | |
sg(netio,'setport 2.0') | |
sg(netio,'setport 3.1') | |
time.sleep(0.1) | |
sg(netio,'setport 3.0') | |
sg(netio,'setport 4.1') | |
time.sleep(0.1) | |
sg(netio,'setport 4.0') | |
time.sleep(0.3) | |
print 'Done initializing.' | |
#netio.close() | |
#======================================================= | |
# For automatic logging: | |
#Connect and get AD values and Status of inputs | |
def getads(netio): | |
try: | |
netio = telnetlib.Telnet(telnethost, telnetport) | |
a1 = int(adc(netio,1)) | |
a2 = int(adc(netio,2)) | |
a3 = int(adc(netio,3)) | |
a4 = int(adc(netio,4)) | |
s = sg(netio,'getstatus') | |
flag = 'OK' | |
except: | |
a1, a2, a3, a4, s = 0, 0, 0, 0, 0 | |
flag = 'Error' | |
netio.close() | |
return a1, a2, a3, a4, s, flag | |
#======================================================= | |
# GUI | |
print 'Starting graphical user interface (GUI)' | |
#Farben für digitale Buttons | |
color_off_bg = 'green' | |
color_off_fg = 'black' | |
color_on_bg = 'yellow' | |
color_on_fg = 'black' | |
def Exit(): | |
global Continue | |
print 'Exit requestet. Stopping program.' | |
Continue = False | |
window = Tkinter.Tk() | |
window['bg'] = 'blue' | |
#window['command'] = Exit | |
window.title('AVR NET-IO') | |
#window.config(width = 200, height = 200) | |
ADC = [] | |
Input = [] | |
Output = [] | |
#Exit/Logging/Refresh block | |
f1 = Tkinter.Frame(window) | |
f1.pack(fill = 'x', side = 'top') | |
#ADC block | |
f2 = Tkinter.Frame(window) | |
f2.pack(side = 'top') | |
#Input/Output block | |
f5 = Tkinter.Frame(window, bg = 'blue', padx = 10, pady = 10) | |
f5.pack(side = 'right') | |
#Refresh slider | |
refresh = Tkinter.Scale(f1, orient='horizontal', length=400, label = 'Refresh interval', cursor = 'hand2', command = window.update()) | |
refresh['from'] = 0 | |
refresh['to'] = 200 | |
refresh.set(Standard_Interval) | |
refresh.pack(side = 'right') | |
#Exit button | |
x = Tkinter.Button(f1, text = 'Exit!', background = 'grey', cursor = 'hand1') | |
x['command'] = Exit | |
x.pack(side = 'left') | |
#Log start button | |
log = Tkinter.Button(f1, text = 'Start logging!', background = 'red', cursor = 'hand2') | |
Logging = False | |
outfile = None | |
def logtoggle(): | |
global Logging | |
global outfile | |
#Switch logging flag | |
Logging = not Logging | |
if Logging: #so we just turned it on | |
if not Logfile_open_close_for_each_entry: #(In that other case the file is opened and closed for each log entry) | |
#Open output file in current directory | |
outfile = open(outfilename, 'a') | |
print 'Logging started into file:', outfilename | |
else: | |
if not Logfile_open_close_for_each_entry: #(In that other case the file is opened and closed for each log entry | |
outfile.close() | |
print 'Logging stopped.' | |
log['command'] = logtoggle | |
log.pack(side = 'left') | |
#Timestamp | |
t = Tkinter.Label(f1, text = "Timestamp: ") | |
t.pack(side = 'top') | |
#Data | |
d = Tkinter.Label(f1, text = "Data: ") | |
d.pack(side = 'top') | |
#Logfile | |
l = Tkinter.Label(f1, text = "Logfile: " + outfilename) | |
l.pack(side = 'top') | |
f3 = Tkinter.Frame(window, bg = 'blue', padx = 10, pady = 10) | |
f3.pack(side='left') | |
f4 = Tkinter.Frame(window, bg = 'red') | |
f4.pack(side='left') | |
#Vier Regler-Widgets für die vier AD-Wandler definieren | |
for i in range(4): | |
ADC.append(Tkinter.Scale(f2, orient='horizontal', length=1024, label='ADC ' + str(i + 1), foreground = 'blue', background = 'green')) | |
ADC[i]['from']=0 | |
ADC[i]['to']=1023 | |
ADC[i].pack() | |
def toggle1(): sg(netio,'setport 1.' + ('1' if Output[0]['bg'] == color_off_bg else '0') ) #einschalten | |
def toggle2(): sg(netio,'setport 2.' + ('1' if Output[1]['bg'] == color_off_bg else '0') ) #einschalten | |
def toggle3(): sg(netio,'setport 3.' + ('1' if Output[2]['bg'] == color_off_bg else '0') ) #einschalten | |
def toggle4(): sg(netio,'setport 4.' + ('1' if Output[3]['bg'] == color_off_bg else '0') ) #einschalten | |
def toggle5(): sg(netio,'setport 5.' + ('1' if Output[4]['bg'] == color_off_bg else '0') ) #einschalten | |
def toggle6(): sg(netio,'setport 6.' + ('1' if Output[5]['bg'] == color_off_bg else '0') ) #einschalten | |
def toggle7(): sg(netio,'setport 7.' + ('1' if Output[6]['bg'] == color_off_bg else '0') ) #einschalten | |
def toggle8(): sg(netio,'setport 8.' + ('1' if Output[7]['bg'] == color_off_bg else '0') ) #einschalten | |
#Acht Buttons für die acht Digitalausgänge definieren | |
for i in range(8): | |
Output.append(Tkinter.Button(f5, cursor = 'hand2')) | |
Output[i].pack(side = 'left') | |
Output[0].config(text='Output 1', command = toggle1) | |
Output[1].config(text='Output 2', command = toggle2) | |
Output[2].config(text='Output 3', command = toggle3) | |
Output[3].config(text='Output 4', command = toggle4) | |
Output[4].config(text='Output 5', command = toggle5) | |
Output[5].config(text='Output 6', command = toggle6) | |
Output[6].config(text='Output 7', command = toggle7) | |
Output[7].config(text='Output 8', command = toggle8) | |
#Vier Kontrollkästchen zur Ausgabe der vier Digitaleingänge definieren | |
for i in range(4): | |
Input.append(Tkinter.Checkbutton(f3)) | |
Input[i].config(text='Input ' + str(i + 1)) | |
Input[i].pack(side = 'left') | |
print 'Displaying values... (abort with Ctrl+C)' | |
Log_count = 0 | |
Continue = True | |
while Continue: | |
timestamp = time.time() | |
#Daten von Board holen | |
a1, a2, a3, a4, Status, flag = getads(netio) | |
#Eingänge abfragen | |
Inputs = 'I' | |
for i in range(4): | |
if sg(netio,'getport ' + str(4-i) ) == '1': | |
Input[i].select() | |
Inputs += '1' | |
else: | |
Input[i].deselect() | |
Inputs += '0' | |
#Timestamp und Daten als Text ausgeben | |
d['text'] = "Data: %4d - %4d - %4d - %4d - %s - %s - %s" % (a1, a2, a3, a4, Status, Inputs, flag) | |
t['text'] = "Timestamp: %.2f" % timestamp | |
#Werte der AD-Wandler als Regler anzeigen | |
ADC[0].set(a1) | |
ADC[1].set(a2) | |
ADC[2].set(a3) | |
ADC[3].set(a4) | |
#Status der Digitalausgänge abfragen und anzeigen | |
#Rückgabeformat: 'S01010011' (S = fest, dann die Bits der Abfrage) | |
for i in range(8): | |
if (Status[8-i] != '0'): #on | |
Output[i]['bg'] = color_on_bg | |
Output[i]['fg'] = color_on_fg | |
else: #off | |
Output[i]['bg'] = color_off_bg | |
Output[i]['fg'] = color_off_fg | |
if not Logging: | |
log.configure(background = 'red', text = 'Start logging') | |
else: #logging is on | |
log.configure(background = 'green', text = 'Stop logging') | |
#log values | |
if Logfile_open_close_for_each_entry: outfile = open(outfilename, 'a') | |
Log_count += 1 | |
outfile.write( str(time.time()) + '\t' + str(Log_count) + '\t' + str(a1) + '\t' + str(a2) + '\t' + str(a3) + '\t' + str(a4) + '\t' + Status + '\t' + Inputs + '\t' + flag + '\n' ) #And write them to logfile | |
if Logfile_open_close_for_each_entry: outfile.close() | |
window.update() | |
wait = refresh.get() / 100.0 | |
refresh['label'] = 'Wait time between queries: %.2f s' % wait | |
time.sleep( wait ) | |
# Set your logging parameters here: | |
#outfilename = 'avrnetio.log' | |
#loginterval = 30 #seconds | |
#Endless logging loop which prints values and writes them to a file. | |
#i = 0 #Counter of logged values since start of script. | |
#t0=time.time() #One of the time correction variables | |
#while True: #Set a limit if you want | |
#i += 1 | |
#print time.time(), '-', i, '-', #Start log line with unix timestamp (with second fractions), and counter | |
#a1, a2, a3, a4, s, flag = getads(netio) #Get input values from controller | |
#print a1, '-', a2, '-', a3, '-', a4, '-', s, '-', flag #Print them | |
#outfile.write( str(time.time()) + '\t' + str(i) + '\t' + str(a1) + '\t' + str(a2) + '\t' + str(a3) + '\t' + str(a4) + '\t' + str(s) + '\t' + flag + '\n' ) #And write them to logfile | |
#t1=time.time() #These lines correct for execution time of loop in order to get equidistant intervalls. | |
#t2=time.time() | |
#time.sleep(loginterval - (t1-t0 - (t2-t1)) ) #Sleep for time corrected interval | |
#t0=time.time() | |
#Properly close file, if loop is left while logging | |
if outfile and not Logfile_open_close_for_each_entry: | |
outfile.close() | |
netio.close() | |
print 'Done. Goodbye!' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment