Python - Rob Faludi

advertisement
WFE603
Programming in Python
Rob Faludi
Collaborative Strategy Leader
Session Overview
•
•
•
•
Problem Statement
Python Programming Language (v. 2.4)
Python on Digi devices
Digi ESP
The Problem
• Putting application intelligence in the right
places
• Writing simply
• Writing experimentally
• Writing powerfully
Where’s Your Application?
• Open-source, flexible language that puts
decision-making smarts on a gateway
• Very simply to write basic code
• Easy to experiment interactively
• Powerful extensions
• Broad support
•
•
•
•
•
•
•
•
•
High-level
Readable
Dynamically typed
Automatic memory management
Scripting, OOP, functions
Extensible
Powerful
Portable
Free
Zen of Python
•
•
•
•
•
•
•
•
•
•
•
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to
break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
•
•
•
•
•
•
•
•
In the face of ambiguity, refuse the
temptation to guess.
There should be one-- and preferably
only one --obvious way to do it.
Although that way may not be
obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than
*right* now.
If the implementation is hard to
explain, it's a bad idea.
If the implementation is easy to
explain, it may be a good idea.
Namespaces are one honking great
idea -- let's do more of those!
• Less is more
– Less to type
– Less to debug
– Less to maintain
• Productivity
Lots of Resources
•
Online
–
–
–
•
Python.org (http://docs.python.org)
Dive Into Python (http://diveintopython.org)
Python Challenge (http://www.pythonchallenge.com)
Books
–
–
–
Learning Python by Mark Lutz
Programming Python by Mark Lutz
Python Cookbook by Alex Martelli, Anna Martelli
Ravenscroft, David Ascher
A basic program
def hello():
"""Prints a salutation to the
user"""
# Say hello
print "Hello World!"
if __name__ == "__main__":
hello()
Note that indentation dictates structure, not keywords or
special tokens.
Really basic
print "Hello World!"
Python is about getting work done
print "Hello World!"
print 2+2
foo="bar"
print foo
Indentation Matters
if 1+1==2:
print "answer correct!"
print "you did math!"
if 1+1==3:
print "answer correct"
print "you did math!"
Core Data Types
•
•
•
•
•
•
Numbers
Strings
Lists
Dictionaries
Tuples
Files
Data types – Scalars
•
Numbers
–
–
–
–
–
–
•
5 /2 = 2
5.0 / 2 = 2.5
from __future__ import division
bool
–
•
Three types (int, float and long)
Varying representations (10, 0xa, 012)
Don't worry too much about type (except division)
Values ( True and False )
None
Container Objects
•
Sequences
–
–
–
•
Strings: mystring ="abcdefg"
Lists: foo=[1, 'a', None]
Tuples: bar=(1, 'a', None) (immutable)
Mapping
–
Dictionaries: moof={"a": True, 42: 7}
Strings
Normal – "Hello\nThere" (allows escapes)
• Triple-quoted (preserves entered text)
"""Hello
There"""
• Raw – r"Hello\nThere" (escapes ignored)
• Unicode – u"\u0496"(inserts Җ)
– Allows unicode escapes, creates unicode strings, a
different type
•
•
Many native operations plus normal immutable sequence
operations
dir shows available attributes
>>> f= 37.1
>>> g="hello"
>>> dir(f)
['__abs__', '__add__', '__class__', '__coerce__', '__delattr__', '__div__',
'__divmod__', '__doc__', '__eq__', '__float__', '__floordiv__', '__ge__',
'__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__int__',
'__le__', '__long__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__',
'__new__', '__nonzero__', '__pos__', '__pow__', '__radd__', '__rdiv__',
'__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__',
'__rmod__', '__rmul__', '__rpow__', '__rsub__', '__rtruediv__', '__setattr__',
'__str__', '__sub__', '__truediv__']
>>> dir(g)
['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__',
'__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__',
'__gt__', '__hash__', '__init__', '__le__', '__len__', '__lt__', '__mod__',
'__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__rmod__', '__rmul__', '__setattr__', '__str__', 'capitalize', 'center', 'count',
'decode', 'encode', 'endswith', 'expandtabs', 'find', 'index', 'isalnum',
'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust',
'lower', 'lstrip', 'replace', 'rfind', 'rindex', 'rjust', 'rsplit', 'rstrip',
'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate',
'upper', 'zfill’]
Conditional Execution
if <expr>:
<…>
elif <expr>:
<…>
else <expr>:
<…>
There is no goto or case statement in Python
Loops
for <var> in <sequence>:
<…>
while <expr>:
<…>
Variations:
•
break and continue affect looping
•
pass can act as a placeholder
•
(x)range(i[, j[, k]]) is extremely useful for for statements
Functions
def arg_info(arg=42, *pos_args, **kw_args):
"""Doc-string"""
if (arg == 42):
print "arg has default value"
# Print positional arguments
for i in len(pos_args):
# Use string formatting operator
print "Positional argument %d is %v" % (i,
pos_args[i])
print "Keyword arguments"
for key in kw_args.keys():
print "\t", key, ": ", kw_args[key]
return len(pos_args) + len(kw_args)
Modules
•
We already have seen one
# hello.py
def hello():
"""Prints a salutation to the user"""
# Say hello
print "Hello World!"
if __name__ == "__main__":
hello()
import hello
hello.hello()
Importing
•
Styles
–
–
•
from <module> import <name>
import <module> as <alias>
Uses sys.path to find
Exceptions and Error Handling
class ItCantWork(Exception):
pass
def no_work():
raise ValueError
try:
no_work()
except ValueError, e:
# handle exception
does_work()
else:
raise ItCantWork
Homework
•
•
•
•
•
•
Classes
Generators
Iterators
List comprehensions
The standard library
Lots of other useful things…
Using Digi Python
•
Where do I configure Python on the Digi device?
–
Applications -> Python in the WebUI
–
Manage scripts and module files on the device
Configure Python scripts to run automatically on boot
–
Python in iDigi Manager Pro
–
–
Manage scripts and module files on the device
Configure Python scripts to run automatically on boot
–
Python command line tools
–
–
–
set python – Configure automatic start with added options
python – Run scripts manually, or enter an interactive session
Putting Files on the Device
•
Plain Text Files
•
•
use .py extension
upload files
•
iDigi
•
web UI
•
command line interface
Launching a Program
•
Check the Box
•
•
•
•
iDigi
web UI
command line interface
Command Line Launch
•
•
from CLI: set python
or from within Python: import <filename>
set python
Purpose: Configures Python programs to execute on device boot.
Syntax: set python [range=1-4] [state={on|off}]
[command=filename,args]
Options:
range=1-4
Range specifies the index or indices to view or modify with the command.
state={on|off}
When the state is set to on, the specified command is run when the device
boots.
command=filename,args
The program filename to execute and any arguments to pass with the
program, similar to the arguments for the python command. The command
option allows for programs to be run from a TFTP server; however, this usage
is not recommended. If there are spaces to provide arguments, make sure to
wrap the entire command in quotation marks.
Running Interpreter
•
terminal% telnet 192.168.1.200
Trying 192.168.1.200...
Connected to 192.168.1.200
Escape character is '^]'.
•
#> python
•
>>>
•
•
•
Monitoring the System
Management -> Connections
•
•
For monitoring only, can't disconnect Python activity
Equivalent functionality in the CLI is the who command
Checking Resources (Memory)
•
•
The memory of the system is all the memory there is
(no virtual memory), use it wisely.
The rest of the system uses memory as well, leave
some for it (~400-500k at least)
Checking Resources (Sockets)
128 max in the entire system
Garbage Collection
• Simplest:
– Run gc.collect() as often as "you find necessary".
• Tune thresholds (gc.set_threshold)
– "correct" values vary widely per application
• Don't use __del__ methods
• If you must, break cycles manually by
examining gc.garbage periodically and using
your object knowledge to resolve the cycle
Viewing Debug Output
#> set trace state=on mask=printf:*
All sys.stdout and sys.stderr output from your script will be
redirected to the console that ran trace.
Digi Python
XBee® Sockets
Creation:
from socket import *
s = socket(AF_XBEE, SOCK_DGRAM, XBS_PROT_TRANSPORT)
•
•
XBee sockets are datagram sockets like UDP
Maximum packet length depends on radio technology and configuration
Address format:
(address_string, endpoint, profile_id, cluster_id)
zigbee/zb_ex1_hello.py, zb_ex2_rw.py
XBee Module
ddo_command(addr_extended, id[, param, timeout,
order=False, apply=True)
ddo_set_param(…)
ddo_get_param(…) – No param argument
Get/set DDO parameters on XBee modules
–
–
–
–
–
–
addr_extended – Address of node to configure
id – Two letter string identifying parameter
param – New value to set for ddo_command or ddo_set_param
timeout – Max time to wait for response
order – Force this request not to run concurrently
apply – Make changes active (Same as "AC" id)
Returns: ddo_command and ddo_get_param return binary string
configuration value. ddo_set_param returns boolean success. All versions
throw an exception if they cannot reach the radio.
XBee (cont…)
get_node_list(<refresh>) -> list of node objects
• Performs device discovery
– refresh
• False: returns the gateways cache of nodes.
• True: Blocks to perform fresh discovery
• Node object attributes
– type: One of coordinator, router or end
– addr_extended, addr_short: Address representations
– addr_parent: Parent's short address
– profile_id, manufacturer_id: Identifying characteristics
– label: Nodes 'NI' parameter
– device_type: Nodes 'DD' parameter
zigbee/zb_ex4_disc.py
File system
•
•
•
•
Path structure is <VOLUME>/<path>
System volume is WEB
Python modules go in WEB/python
Directory listing/traversal may be limited
– listdir, mkdir will be available in FW version
2.9
• USB volumes progress A, B, ...
– Not guaranteed to enumerate the same each boot
• Python file objects work completely.
Digicli Module
import digicli
digicli.digicli(<cmd>) -> (status,
output)
Run a CLI command
– cmd – Command to run
Returns
– status – False if command failed
– output – list of output lines from execution
Perform a Network Node Discovery
# Perform a node discovery and print out
# the list of discovered nodes to stdio.
# import the zigbee module into its own namespace
import zigbee
# Perform a node discovery:
node_list = zigbee.getnodelist()
# Print the table:
print "%12s %12s %8s %24s" % \
("Label", "Type", "Short", "Extended")
print "%12s %12s %8s %24s" % \
("-" * 12, "-" * 12, "-" * 8, "-" * 24)
for node in node_list:
print "%12s %12s %8s %12s" % \
(node.label, node.type, node.addr_short, node.addr_extended)
Use DDO to Read Temperature
from XBee Sensor
# Collect a sample from a known XBee Sensor adapter
# and parse it into a temperature.
# import zigbee and xbee_sensor modules:
import zigbee
import xbee_sensor
# configure known destination:
DESTINATION="[00:13:a2:00:40:0a:07:8d]!"
# ensure sensor is powered from adapter:
zigbee.ddo_set_param(DESTINATION, 'D2', 5)
zigbee.ddo_set_param(DESTINATION, 'AC', '')
# get and parse sample:
sample = zigbee.ddo_get_param(DESTINATION, '1S')
xbee_temp = xbee_sensor.XBeeWatchportT()
xbee_temp.parse_sample(sample)
print "Temperature is: %f degrees Celsius" % (xbee_temp.temperature)
Digicli Example
import digicli
status, output = digicli.digicli('show net')
if status:
for line in output:
if line.find('MAC Address') >= 0:
l = line.split(':')
print "".join(l[1:]).strip()import
digicli
digicli.digicli(<cmd>) -> (status, output)
The Digi ESP
The Digi ESP
•
•
•
•
•
•
•
•
•
An IDE used across several product lines, built on top of Eclipse
Facilitates development with Digi products
Distributed as a built-in product (not as plug-ins)
Powerful editing capabilities (syntax highlight, auto completion,
syntax verification, …); Code builders and checkers; Integrated
symbolic debugger
Example/Project wizards
Configuration tools
Extended through custom plug-ins to provide a better integration
with our products
Bundled with other components needed like JVM, Python
interpreters, etc
Multiplatform (runs on MS Windows, Linux and Mac)
The Digi ESP
ESP flavors
Digi ESP for Python
• Complete and simplified development process:
–
–
–
–
–
Easy-to-use project wizards
Python source code and Smart iDigi Dia Editor
Build management
Remote launch/debug
Application deployment
• Built-in iDigi support
• Full integrated help with interactive tutorials
• Additional tools:
–
–
–
–
–
Device discovery (USB, LAN and iDigi)
Remote file explorer
Channel explorer
Terminal consoles
Package manager
Package Manager
•
•
•
•
Digi ESP software distribution/upgrade plug-in
Allows the access to the different software packages available on the PkM
server, available for that specific ESP flavor, accordingly to the privileges
provided by the installed PkM license(s)
Packages are created by Digi engineers which are later posted to the
Package Manager server, making them available to all Digi ESP users
Package Types:
– New features
– Fixes
– Documentation
– Updates
– Other
Digi
Package Manager Server
Digi ESP
for
Python
Internet
Digi ESP for NET+OS
Digi ESP for
Embedded
Linux
Getting ESP
• www.digi.com/esp
Using ESP
•
•
•
•
•
connecting devices
Hello World
SMTP
HTTP
Dia Example
Digi Python Samples
Connect a Device
Hello World
"""\
Hello World! demo for Digi devices
This example prints out a "Hello
World!" message to stdout.
"""
import sys, os
print "Hello World!"
SMTP Alarm
SMTP_Server = "email.mydomain.com" #hostname of the SMTP
server
sender_email = "test@digi.com" #The sender's email address
recipient_email = "my@email.com" #The destination email
address
subject = "Value Detect test" #Subject of the email
msg_format = 'The value is now: %s' #The body of the email,
the sample will
#replace the %s in this
message.
print "Creating alarm"
email_alarm = alarm.SMTPAlarm(alarm_function,
msg_format,
debounce_function,
SMTP_Server,
sender_email,
recipient_email,
subject)
Fetch Web Page
"def main():
# Open the web page.
fhandler = urllib.urlopen(WEB_PAGE)
# Print some details about the page retrieved
page_info = fhandler.info()
print "Retrieved '%s'\r\n" %fhandler.geturl()
for item in page_info.items():
print "%s : %s" %(item[0], item[1])
print "\r\nPage content:"
# Start reading and printing the content of the web
page.
while True:
data = fhandler.read(1024)
if len(data) == 0:
break
sys.stdout.write(data)
Dia
Using Digi Python
•
•
Where can I get more information?
–
Digi developer Wiki (http://www.digi.com/wiki/developer)
–
"Digi Python Programmer's Guide" in particular
–
Digi support forum (http://www.digi.com/support/forum)
–
Drop-In Networking -> Software -> Python
What version of Python should I use?
–
–
Python 2.4 for Digi NDS devices.
Python 2.7 for Digi X2E devices.
THANK YOU!
Rob Faludi
rob.faludi@digi.com
Download