I created a simple network in the mininet environment with the following command:
$ sudo mn --topo single,3 --mac --controller remote --switch ovsk
I want use RYU CONTROLLER to calculate bandwidth traffic on special port of switch. I'm thinking of using an OFPEVENTPacketIn event for the incoming packet, but I do not any idea for out coming packet form port.
My code:
from operator import attrgetter
from ryu.app import simple_switch_13
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER, DEAD_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.lib import hub
class SimpleMonitor(simple_switch_13.SimpleSwitch13):
def __init__(self, *args, **kwargs):
super(SimpleMonitor, self).__init__(*args, **kwargs)
self.datapaths = {}
self.monitor_thread = hub.spawn(self._monitor)
#set_ev_cls(ofp_event.EventOFPStateChange,
[MAIN_DISPATCHER, DEAD_DISPATCHER])
def _state_change_handler1(self, ev):
datapath = ev.datapath
if ev.state == MAIN_DISPATCHER:
if not datapath.id in self.datapaths:
self.logger.debug('register datapath: %016x', datapath.id)
self.datapaths[datapath.id] = datapath
elif ev.state == DEAD_DISPATCHER:
if datapath.id in self.datapaths:
self.logger.debug('unregister datapath: %016x', datapath.id)
del self.datapaths[datapath.id]
def _monitor(self):
while True:
for dp in self.datapaths.values():
self._request_stats(dp)
hub.sleep(10)
def _request_stats(self, datapath):
self.logger.debug('send stats request: %016x', datapath.id)
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
req = parser.OFPFlowStatsRequest(datapath)
datapath.send_msg(req)
req = parser.OFPPortStatsRequest(datapath, 0, ofproto.OFPP_ANY)
datapath.send_msg(req)
#set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
def _flow_stats_reply_handler(self, ev):
body = ev.msg.body
self.logger.info('datapath '
'in-port eth-dst '
'out-port packets bytes')
self.logger.info('---------------- '
'-------- ----------------- '
'-------- -------- --------')
for stat in sorted([flow for flow in body if flow.priority == 1],
key=lambda flow: (flow.match['in_port'],
flow.match['eth_dst'])):
# self.logger.info('%016x %8x %17s %8x %8d %8d',
if stat.match['in_port']==1:
self.logger.info('%x %x %s %x %d %d',
ev.msg.datapath.id,
stat.match['in_port'], stat.match['eth_dst'],
stat.instructions[0].actions[0].port,
stat.packet_count, stat.byte_count)
#for stat in [1234]#sorted([flow for flow in body if flow.priority == 1],
# key=lambda flow: (flow.match['in_port'],
# flow.match['eth_dst'])):
# self.logger.info('%016x %8x %17s %8x %8d %8d',
# if stat.match['in_port']==1:
# self.logger.info('%x %x %s %x %d %d',
# ev.msg.datapath.id,
# stat.match['in_port'], stat.match['eth_dst'],
# stat.instructions[0].actions[0].port,
# stat.packet_count, stat.byte_count)
#set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
def _port_stats_reply_handler(self, ev):
body = ev.msg.body
self.logger.info('datapath port '
'rx-pkts rx-bytes rx-error '
'tx-pkts tx-bytes tx-error')
self.logger.info('---------------- -------- '
'-------- -------- -------- '
'-------- -------- --------')
for stat in sorted(body, key=attrgetter('port_no')):
if stat.port_no==1:
self.logger.info('%016x %8x %8d %8d %8d %8d %8d %8d',
ev.msg.datapath.id, stat.port_no,
stat.rx_packets, stat.rx_bytes, stat.rx_errors,
stat.tx_packets, stat.tx_bytes, stat.tx_errors)
Please help me edit this code to answer my question. Thanks.
You have to add two method in your controller:
1) a method that requests stats
2) a method that captures the answers from switches.
The method for answering stats is the following:
def send_flow_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
cookie = cookie_mask = 0
match = ofp_parser.OFPMatch(in_port=1)
req = ofp_parser.OFPFlowStatsRequest(datapath, 0,
ofp.OFPTT_ALL,
ofp.OFPP_ANY, ofp.OFPG_ANY,
cookie, cookie_mask,
match)
datapath.send_msg(req)
The method for capturing answers is this one:
#set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
def flow_stats_reply_handler(self, ev):
flows = []
for stat in ev.msg.body:
flows.append('table_id=%s '
'duration_sec=%d duration_nsec=%d '
'priority=%d '
'idle_timeout=%d hard_timeout=%d flags=0x%04x '
'cookie=%d packet_count=%d byte_count=%d '
'match=%s instructions=%s' %
(stat.table_id,
stat.duration_sec, stat.duration_nsec,
stat.priority,
stat.idle_timeout, stat.hard_timeout, stat.flags,
stat.cookie, stat.packet_count, stat.byte_count,
stat.match, stat.instructions))
self.logger.debug('FlowStats: %s', flows)
Once you capture stats you can compute bandwidth usage.
However you have also other kind of requests you can perform so i suggest you to read the rye doc.
http://ryu.readthedocs.io/en/latest/
Related
I'm trying to make a simple python script to ping all devices in my company, but I stuck in pinging between two networks: 192.168.0.x and 192.168.10.x
Is there a way to ping addresses in 192.168.10.x from 192.168.0.x without making changes in LAN configuration?
from pythonping import ping
ips = ['192.168.0.88', '192.168.0.253', '192.168.0.182', '192.168.0.9', '192.168.0.1', '192.168.10.10',
'192.168.10.5']
def check_by_ping(ip=[]):
ret = []
for ip in ips:
p = ping(ip, count=1)
if p.rtt_max_ms == 2000:
ret.append([ip, False])
print('Wynik: ', ip, ' = ', 'Nieosiągalne!!!')
else:
ret.append([ip, p.rtt_max_ms])
print('Wynik: ', ip, ' = ', p.rtt_max_ms)
return ret
c = 0
while c<100:
print('\n Test nr: ',c,'\n')
check_by_ping(ips)
c += 1
i have a problem with drop table after finish my scenario
when I try to delete using db.drop_table(Routes, if_exists=False, with_all_data=False) or db.drop_table(Routes, if_exists=True, with_all_data=True)
i get an error
pony.orm.core.TransactionError: #db_session-decorated drop_table() function with ddl option cannot be called inside of another db_sessio
i try to delete using Routes.delete() and I got the same one
i read more documentation and i dont know how can i drop this table
my full code
import logging
import random
import requests
import vk_api
from pony.orm import db_session, rollback
from vk_api.bot_longpoll import VkBotLongPoll, VkBotEventType
import handlers
from models import UserState, Registration, Routes, db
try:
import settings
except ImportError:
exit('DO CP settings.py.default setting.py and set token')
log = logging.getLogger('bot')
def configure_logging():
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(logging.Formatter('%(levelname)s %(message)s'))
stream_handler.setLevel(logging.INFO)
log.addHandler(stream_handler)
file_handler = logging.FileHandler('bot.log')
file_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s'))
file_handler.setLevel(logging.DEBUG)
log.addHandler(file_handler)
class Bot:
"""
Echo bot for vk.com
Use python 3.7
"""
def __init__(self, group_id, token):
"""
:param group_id:group_id from group vk.com
:param token:secret key
"""
self.group_id = group_id
self.token = token
self.vk = vk_api.VkApi(token=self.token)
self.long_poller = VkBotLongPoll(self.vk, self.group_id)
self.api = self.vk.get_api()
def run(self):
"""run bot"""
for event in self.long_poller.listen():
try:
print(event)
self.on_event(event)
except Exception:
log.exception('ошибка в обработке события')
#db_session
def on_event(self, event):
"""
sends the message back, if message text
:param event: VKBotMessageEvent object
:return: None
"""
if event.type != VkBotEventType.MESSAGE_NEW:
log.info('пока не умеем работать с таким типом события %s', event.type)
return
user_id = event.message.peer_id
text = event.message.text
state = UserState.get(user_id=str(user_id))
if state is not None:
self.continue_scenario(text=text, state=state, user_id=user_id)
else:
# search intent, the user is found outside of the scenario
for intent in settings.INTENTS:
log.debug(f'User gets {intent}')
if any(token in text.lower() for token in intent['tokens']):
# run intent
if intent['answer']:
self.send_text(text_to_send=intent['answer'], user_id=user_id)
else:
self.start_scenario(scenario_name=intent['scenario'], user_id=user_id, text=text)
break
else:
self.send_text(text_to_send=settings.DEFAULT_ANSWER, user_id=user_id)
# функция отправки текста
def send_text(self, text_to_send, user_id):
self.api.messages.send(
message=text_to_send,
random_id=random.randint(0, 2 ** 20),
peer_id=user_id)
# функция отправки изображения
def send_image(self, image, user_id):
upload_url = self.api.photos.getMessagesUploadServer()['upload_url']
upload_data = requests.post(url=upload_url, files={'photo': ('image.png', image, 'image/png')}).json()
image_data = self.api.photos.saveMessagesPhoto(**upload_data)
owner_id = image_data[0]['owner_id']
media_id = image_data[0]['id']
attachment = f'photo{owner_id}_{media_id}'
self.api.messages.send(
attachment=attachment,
random_id=random.randint(0, 2 ** 20),
peer_id=user_id)
# функция отправки маршрутов
def send_routes(self, text_to_send, user_id):
self.api.messages.send(
message=text_to_send,
random_id=random.randint(0, 2 ** 20),
peer_id=user_id)
# шаг отправки
def send_step(self, step, user_id, text, context):
if 'text' in step:
self.send_text(text_to_send=step['text'].format(**context), user_id=user_id)
if 'image' in step:
handler = getattr(handlers, step['image'])
image = handler(text=text, context=context)
self.send_image(image=image, user_id=user_id)
if 'choice' in step:
handler = getattr(handlers, step['choice'])
choices = handler(text=text, context=context)
for i, choice in enumerate(choices, start=1):
city_from = context['city_from']
city_to = context['city_to']
flight_time = choice[city_from][city_to][0]
flight_board = choice[city_from][city_to][1]
flight_date = choice[city_from][city_to][2]
number_choice = str(i) + ') '
Routes(number_choice=number_choice, flight_time=flight_time, city_from=city_from, city_to=city_to,
flight_board=flight_board, flight_date=flight_date)
select = db.select('number_choice,flight_time,city_from,city_to,flight_board,flight_date FROM Routes')
text_to_send = ' '.join(select[0]) + '\n' + ' '.join(select[1]) + '\n' + ' '.join(
select[2]) + '\n' + ' '.join(
select[3]) + '\n' + ' '.join(select[4]) + '\n'
self.send_routes(text_to_send=text_to_send, user_id=user_id)
# начало сценария
def start_scenario(self, scenario_name, user_id, text):
scenario = settings.SCENARIOS[scenario_name]
first_step = scenario['first_step']
step = scenario['steps'][first_step]
self.send_step(step=step, user_id=user_id, text=text, context={})
UserState(user_id=str(user_id), scenario_name=scenario_name, step_name=first_step, context={})
# конец сценария
def continue_scenario(self, text, state, user_id):
steps = settings.SCENARIOS[state.scenario_name]['steps']
step = steps[state.step_name]
handler = getattr(handlers, step['handler'])
if handler(text=text, context=state.context):
# next_step
if step['handler'] != 'handler_answer':
self.walking_through_scenario(state=state, step=step, steps=steps, text=text, user_id=user_id)
else:
if state.context['answer'] == 'да':
self.walking_through_scenario(state=state, step=step, steps=steps, text=text, user_id=user_id)
else:
next_step = step['failure_step']
state.delete()
self.send_step(step=step, user_id=user_id, text=text, context={})
UserState(user_id=str(user_id), scenario_name=state.scenario_name, step_name=next_step, context={})
else:
# retry_current_step
text_to_send = step['failure_text'].format(**state.context)
self.send_text(text_to_send=text_to_send, user_id=user_id)
# движения по сценарию
def walking_through_scenario(self, state, step, steps, text, user_id):
next_step = steps[step['next_step']]
self.send_step(step=next_step, user_id=user_id, text=text, context=state.context)
if next_step['next_step']:
# switch to next step
state.step_name = step['next_step']
else:
# finish scenario and delete user states
log.info(
'Зарегистрирован пользователь ФИО {name} следует из {city_from} в {city_to} телефон для контактов {phone} '.format(
**state.context))
Registration(name=state.context['name'], city_from=state.context['city_from'],
city_to=state.context['city_to'],
phone=state.context['phone'])
state.delete()
if __name__ == '__main__':
configure_logging()
bot = Bot(group_id=settings.GROUP_ID, token=settings.TOKEN)
bot.run()
it helped me this command Routes.select(lambda p: p.id > 0 ).delete(bulk=True)
Here in California, I have purchased some Nova SDS011 PM sensors. When attempting to read from these sensors using Ivan Kalchev's git repo, I get mixed results. I can send commands to the sensor. e.g. sensor.sleep(sleep=<True/False>) will turn the fan on and off. However attempting to query the sensor to return PM2.5 and PM10 data returns a byte string that does not match the check sum. A couple examples are in the code snip-it below. As you can see, bytes 2 and 6 appear to be corrupt, and furthermore, the response is two bytes shorter than what is expected from the documentation.
Any Idea whats going on here? Im hoping this is simply a problem with pyserial. I have produced the same results with two sensors.
>>> sensor.sleep(sleep=False)
>>> cmd
'\xaa\xb4\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x02\xab'
>>> sensor.ser.write(cmd)
19
>>> sensor.ser.readline()
'\xaa\xc0]\x01\xba\x01\xc2*\x05\xab'
>>> sensor.ser.write(cmd)
19
>>> sensor.ser.readline()
'\xaa\xc0c\x01\xbc\x01\xc2*\r\xab'
>>> sensor.ser.write(cmd)
19
>>> sensor.ser.readline()
'\xaa\xc0d\x01\xbf\x01\xc2*\x11\xab'
So this occurred because the python was written for python 3, and my raspberry pi had 2.7. below is the code for 2.7. Thanks to Ivan for putting the original together.
"""This module provides an abstraction for the SDS011 air partuclate densiry sensor.
"""
import struct
import serial
#TODO: Commands against the sensor should read the reply and return success status.
class SDS011(object):
"""Provides method to read from a SDS011 air particlate density sensor
using UART.
"""
HEAD = b'\xaa'
TAIL = b'\xab'
CMD_ID = b'\xb4'
# The sent command is a read or a write
READ = b"\x00"
WRITE = b"\x01"
REPORT_MODE_CMD = b"\x02"
ACTIVE = b"\x00"
PASSIVE = b"\x01"
QUERY_CMD = b"\x04"
# The sleep command ID
SLEEP_CMD = b"\x06"
# Sleep and work byte
SLEEP = b"\x00"
WORK = b"\x01"
# The work period command ID
WORK_PERIOD_CMD = b'\x08'
def __init__(self, serial_port, baudrate=9600, timeout=2,
use_query_mode=True):
"""Initialise and open serial port.
"""
self.ser = serial.Serial(port=serial_port,
baudrate=baudrate,
timeout=timeout)
self.ser.flush()
self.set_report_mode(active=not use_query_mode)
def _execute(self, cmd_bytes):
"""Writes a byte sequence to the serial.
"""
self.ser.write(cmd_bytes)
def _get_reply(self):
"""Read reply from device."""
raw = self.ser.read(size=10)
data = raw[2:8]
if len(data) == 0:
return None
if (sum(ord(d) for d in data) & 255) != ord(raw[8]):
return None #TODO: also check cmd id
return raw
def cmd_begin(self):
"""Get command header and command ID bytes.
#rtype: list
"""
return self.HEAD + self.CMD_ID
def set_report_mode(self, read=False, active=False):
"""Get sleep command. Does not contain checksum and tail.
#rtype: list
"""
cmd = self.cmd_begin()
cmd += (self.REPORT_MODE_CMD
+ (self.READ if read else self.WRITE)
+ (self.ACTIVE if active else self.PASSIVE)
+ b"\x00" * 10)
cmd = self._finish_cmd(cmd)
self._execute(cmd)
self._get_reply()
def query(self):
"""Query the device and read the data.
#return: Air particulate density in micrograms per cubic meter.
#rtype: tuple(float, float) -> (PM2.5, PM10)
"""
cmd = self.cmd_begin()
cmd += (self.QUERY_CMD
+ b"\x00" * 12)
cmd = self._finish_cmd(cmd)
self._execute(cmd)
raw = self._get_reply()
if raw is None:
return None #TODO:
data = struct.unpack('<HH', raw[2:6])
pm25 = data[0] / 10.0
pm10 = data[1] / 10.0
return (pm25, pm10)
def sleep(self, read=False, sleep=True):
"""Sleep/Wake up the sensor.
#param sleep: Whether the device should sleep or work.
#type sleep: bool
"""
cmd = self.cmd_begin()
cmd += (self.SLEEP_CMD
+ (self.READ if read else self.WRITE)
+ (self.SLEEP if sleep else self.WORK)
+ b"\x00" * 10)
cmd = self._finish_cmd(cmd)
self._execute(cmd)
self._get_reply()
def set_work_period(self, read=False, work_time=0):
"""Get work period command. Does not contain checksum and tail.
#rtype: list
"""
assert work_time >= 0 and work_time <= 30
cmd = self.cmd_begin()
cmd += (self.WORK_PERIOD_CMD
+ (self.READ if read else self.WRITE)
+ bytes([work_time])
+ b"\x00" * 10)
cmd = self._finish_cmd(cmd)
self._execute(cmd)
self._get_reply()
def _finish_cmd(self, cmd, id1=b"\xff", id2=b"\xff"):
"""Add device ID, checksum and tail bytes.
#rtype: list
"""
cmd += id1 + id2
checksum = sum(d for d in bytearray(cmd[2:])) % 256
cmd += chr(checksum) + self.TAIL
return cmd
def _process_frame(self, data):
"""Process a SDS011 data frame.
Byte positions:
0 - Header
1 - Command No.
2,3 - PM2.5 low/high byte
4,5 - PM10 low/high
6,7 - ID bytes
8 - Checksum - sum of bytes 2-7
9 - Tail
"""
raw = struct.unpack('<HHxxBBB', data[2:])
checksum = sum(v for v in bytearray(data[2:8])) % 256
if checksum != data[8]:
return None
pm25 = raw[0] / 10.0
pm10 = raw[1] / 10.0
return (pm25, pm10)
def read(self):
"""Read sensor data.
#return: PM2.5 and PM10 concetration in micrograms per cude meter.
#rtype: tuple(float, float) - first is PM2.5.
"""
byte = 0
while byte != self.HEAD:
byte = self.ser.read(size=1)
d = self.ser.read(size=10)
if d[0:1] == b"\xc0":
data = self._process_frame(byte + d)
return data
I have put together a custom formatter for a logger and I am using pyspark, but it looks like all of my color is removed on the command-line. I can confirm that the escape sequences are present within the record of each emitted value, but it appears that they're stripped when sent to the terminal.
Why?
import datetime
import logging
import colorama
from pygments import highlight
from pygments.lexers import JsonLexer
from pygments.formatters import Terminal256Formatter
# Required for colored output
colorama.init()
class CustomFormatter(logging.Formatter):
'''Modifies the level prefix of the log with the following level
information:
!!! - critical
! - error
? - warn
- info
- - debug
'''
default_prefix = '???' # used with non-generic levels
color_mapping = {
logging.CRITICAL: colorama.Fore.RED + colorama.Style.BRIGHT,
logging.ERROR: colorama.Fore.RED + colorama.Style.BRIGHT,
logging.WARNING: colorama.Fore.YELLOW + colorama.Style.BRIGHT,
logging.DEBUG: colorama.Style.DIM,
}
prefix_mapping = {
logging.CRITICAL: '!!!',
logging.ERROR: ' ! ',
logging.WARNING: ' ? ',
logging.INFO: ' ',
logging.DEBUG: ' · ',
}
def format(self, record):
# Capture relevant record data
level = self.prefix_mapping.get(record.levelno) or self.default_prefix
msecs = datetime.datetime.fromtimestamp(record.created).strftime("%Y-%m-%d %H:%M:%S")
msg = record.msg.rstrip('\n')
# Setup colors
color = self.color_mapping.get(record.levelno) or ''
dim = colorama.Style.DIM
reset = colorama.Fore.RESET + colorama.Style.RESET_ALL
name = record.name
func = record.funcName
# Setup output
lexer = JsonLexer()
formatter = Terminal256Formatter()
try:
msg = '\n'.join(
highlight(m, lexer, formatter).rstrip('\n')
for m in msg.split('\n')
)
except:
pass
data = {k: v for k, v in locals().items()}
d = '{color}{level}{reset} {dim}{msecs} [{name}]{reset} {msg}'.format(**data)
record.msg = d
# Dump
return super(CustomFormatter, self).format(record)
Usage:
import logging
from CustomFormatter import CustomFormatter
def get_logger(name, level=None):
level = logging.DEBUG if not isinstance(level, int) else level
handler = logging.StreamHandler(sys.stdout)
handler.level = level or logging.INFO
formatter = CustomFormatter()
handler.setFormatter(formatter)
logger = logging.getLogger(name)
logger.addHandler(handler)
return logger
logger = get_logger('tester')
logger.error('Error here')
I spent some time digging into this, and I found that the terminal escape sequences are different when loading under pyspark. The way I fixed it is by using pygments to run over the terminal output I created (see function: fix_for_spark).
# -*- coding: utf-8 -*-
import datetime
import json
import logging
import os
import colorama
from pygments import highlight
from pygments.lexers import JsonLexer
from pygments.formatters import Terminal256Formatter
# Required for colored output
colorama.init()
class CustomFormatter(logging.Formatter):
'''Modifies the level prefix of the log with the following level
information:
!!! - critical
! - error
? - warn
- info
- - debug
'''
default_prefix = '???' # used with non-generic levels
PYGMENTS_LEXER = JsonLexer()
PYGMENTS_FORMATTER = Terminal256Formatter()
color_mapping = {
logging.CRITICAL: colorama.Fore.RED + colorama.Style.BRIGHT,
logging.ERROR: colorama.Fore.RED + colorama.Style.BRIGHT,
logging.WARNING: colorama.Fore.YELLOW + colorama.Style.BRIGHT,
logging.DEBUG: colorama.Style.DIM,
}
prefix_mapping = {
logging.CRITICAL: '!!!',
logging.ERROR: ' ! ',
logging.WARNING: ' ? ',
logging.INFO: ' ️ ',
logging.DEBUG: ' · ',
}
def fix_for_spark(self, string):
if os.environ.get('SPARK_ENV_LOADED'):
# Setup output
new_string = []
for s in string.split('\n'):
s = highlight(string, self.PYGMENTS_LEXER, self.PYGMENTS_FORMATTER)
new_string.append(s.rstrip('\n'))
string = '\n'.join(new_string)
return string
def format(self, record):
# Capture relevant record data
data = dict(
level=self.prefix_mapping.get(record.levelno) or self.default_prefix,
msecs=datetime.datetime.fromtimestamp(record.created).strftime("%Y-%m-%d %H:%M:%S"),
# Setup colors
color=self.color_mapping.get(record.levelno) or '',
dim=colorama.Style.DIM,
reset=colorama.Fore.RESET + colorama.Style.RESET_ALL,
name=record.name,
func=record.funcName,
)
# Format msg
prefix = '{color}{level}{reset} {dim}{msecs}{reset} {color}[{name}]{reset}'
prefix = prefix.format(**data)
prefix = self.fix_for_spark(prefix)
msg = record.msg
if not isinstance(msg, str):
try:
msg = json.dumps(msg, indent=4, sort_keys=True)
except:
msg = str(msg)
dmsg = []
for m in msg.split('\n'):
m = highlight(m, self.PYGMENTS_LEXER, self.PYGMENTS_FORMATTER).rstrip('\n')
m = self.fix_for_spark(m)
dmsg.append(m)
dmsg = '\n'.join(dmsg)
data.update(locals().items())
template = prefix + ' {msg}'
record.msg = '\n'.join(template.format(msg=m) for m in dmsg.split('\n'))
# Dump
return super(CustomFormatter, self).format(record)
I have 3 files lcdtest.py, lcd.py and alarmfunctionr.py.
I am trying to control the attached lcd display on my raspberry pi with the lcdtest.py script.
!/usr/bin/env python
import paho.mqtt.client as paho
import globals
import time
from alarmfunctionsr import SendToLCD
from lcd import noDisplay
from lcd import message
globals.init()
SendToLCD(12, "test lcd" ,1) #Test
time.sleep(5)
lcd.message("test with message")
time.sleep(5)
noDisplay
The import from alarmfunctionsr seem to work ok but i get an cannot import name error when i try the same for the lcd script.
lcd.py:
#!/usr/bin/python
#
# based on code from lrvick and LiquidCrystal
# lrvic - https://github.com/lrvick/raspi-hd44780/blob/master/hd44780.py
# LiquidCrystal - https://github.com/arduino/Arduino/blob/master/libraries/LiquidCrystal/LiquidCrystal.cpp
#
from time import sleep
class CharLCD(object):
# commands
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR = 0x40
LCD_SETDDRAMADDR = 0x80
# flags for display entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00
# flags for display on/off control
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON = 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF = 0x00
# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00
# flags for function set
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5x10DOTS = 0x04
LCD_5x8DOTS = 0x00
def __init__(self, pin_rs=25, pin_e=24, pins_db=[23, 17, 27, 22], GPIO=None):
# Emulate the old behavior of using RPi.GPIO if we haven't been given
# an explicit GPIO interface to use
if not GPIO:
import RPi.GPIO as GPIO
GPIO.setwarnings(False)
self.GPIO = GPIO
self.pin_rs = pin_rs
self.pin_e = pin_e
self.pins_db = pins_db
self.GPIO.setmode(GPIO.BCM)
self.GPIO.setup(self.pin_e, GPIO.OUT)
self.GPIO.setup(self.pin_rs, GPIO.OUT)
for pin in self.pins_db:
self.GPIO.setup(pin, GPIO.OUT)
self.write4bits(0x33) # initialization
self.write4bits(0x32) # initialization
self.write4bits(0x28) # 2 line 5x7 matrix
self.write4bits(0x0C) # turn cursor off 0x0E to enable cursor
self.write4bits(0x06) # shift cursor right
self.displaycontrol = self.LCD_DISPLAYON | self.LCD_CURSOROFF | self.LCD_BLINKOFF
self.displayfunction = self.LCD_4BITMODE | self.LCD_1LINE | self.LCD_5x8DOTS
self.displayfunction |= self.LCD_2LINE
# Initialize to default text direction (for romance languages)
self.displaymode = self.LCD_ENTRYLEFT | self.LCD_ENTRYSHIFTDECREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode) # set the entry mode
self.clear()
def begin(self, cols, lines):
if (lines > 1):
self.numlines = lines
self.displayfunction |= self.LCD_2LINE
def home(self):
self.write4bits(self.LCD_RETURNHOME) # set cursor position to zero
self.delayMicroseconds(3000) # this command takes a long time!
def clear(self):
self.write4bits(self.LCD_CLEARDISPLAY) # command to clear display
self.delayMicroseconds(3000) # 3000 microsecond sleep, clearing the display takes a long time
def setCursor(self, col, row):
self.row_offsets = [0x00, 0x40, 0x14, 0x54]
self.write4bits(self.LCD_SETDDRAMADDR | (col + self.row_offsets[row]))
def noDisplay(self):
""" Turn the display off (quickly) """
self.displaycontrol &= ~self.LCD_DISPLAYON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def display(self):
""" Turn the display on (quickly) """
self.displaycontrol |= self.LCD_DISPLAYON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def noCursor(self):
""" Turns the underline cursor off """
self.displaycontrol &= ~self.LCD_CURSORON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def cursor(self):
""" Turns the underline cursor on """
self.displaycontrol |= self.LCD_CURSORON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def noBlink(self):
""" Turn the blinking cursor off """
self.displaycontrol &= ~self.LCD_BLINKON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def blink(self):
""" Turn the blinking cursor on """
self.displaycontrol |= self.LCD_BLINKON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def DisplayLeft(self):
""" These commands scroll the display without changing the RAM """
self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVELEFT)
def scrollDisplayRight(self):
""" These commands scroll the display without changing the RAM """
self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVERIGHT)
def leftToRight(self):
""" This is for text that flows Left to Right """
self.displaymode |= self.LCD_ENTRYLEFT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
def rightToLeft(self):
""" This is for text that flows Right to Left """
self.displaymode &= ~self.LCD_ENTRYLEFT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
def autoscroll(self):
""" This will 'right justify' text from the cursor """
self.displaymode |= self.LCD_ENTRYSHIFTINCREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
def noAutoscroll(self):
""" This will 'left justify' text from the cursor """
self.displaymode &= ~self.LCD_ENTRYSHIFTINCREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
def write4bits(self, bits, char_mode=False):
""" Send command to LCD """
self.delayMicroseconds(1000) # 1000 microsecond sleep
bits = bin(bits)[2:].zfill(8)
self.GPIO.output(self.pin_rs, char_mode)
for pin in self.pins_db:
self.GPIO.output(pin, False)
for i in range(4):
if bits[i] == "1":
self.GPIO.output(self.pins_db[::-1][i], True)
self.pulseEnable()
for pin in self.pins_db:
self.GPIO.output(pin, False)
for i in range(4, 8):
if bits[i] == "1":
self.GPIO.output(self.pins_db[::-1][i-4], True)
self.pulseEnable()
def delayMicroseconds(self, microseconds):
seconds = microseconds / float(1000000) # divide microseconds by 1 million for seconds
sleep(seconds)
def pulseEnable(self):
self.GPIO.output(self.pin_e, False)
self.delayMicroseconds(1) # 1 microsecond pause - enable pulse must be > 450ns
self.GPIO.output(self.pin_e, True)
self.delayMicroseconds(1) # 1 microsecond pause - enable pulse must be > 450ns
self.GPIO.output(self.pin_e, False)
self.delayMicroseconds(1) # commands need > 37us to settle
def message(self, text):
""" Send string to LCD. Newline wraps to second line"""
for char in text:
if char == '\n':
self.write4bits(0xC0) # next line
else:
self.write4bits(ord(char), True)
def DisplayLCD(msg):
lcd = CharLCD()
lcd.clear()
x=msg.find("**")
if x>0:
line1=msg[0:x]
line2=msg[x+2:len(msg)]
else:
line1=msg
line2=""
lcd.message(line1+"\n"+line2)
alarmfunctionsr.py:
#!/usr/bin/env python
"""
import globals
import urllib2
import smtplib
import serial
import time
import sys
import thread
import RPi.GPIO as GPIO
import os, glob, time, operator
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from time import sleep
def find_all(a_str, sub):
start = 0
cnt=0
while True:
start = a_str.find(sub, start)
if start == -1:
return cnt
start += len(sub)
cnt=cnt+1
def isNumber(x):
# Test whether the contents of a string is a number
try:
val = int(x)
except ValueError:
return False
return True
def get_latest_photo(files):
lt = operator.lt
if not files:
return None
now = time.time()
latest = files[0], now - os.path.getctime(files[0])
for f in files[1:]:
age = now - os.path.getctime(f)
if lt(age, latest[1]):
latest = f, age
return latest[0]
def UpdateHostThread(function,opcode):
try:
thread.start_new_thread(UpdateHostThread, (function,opcode, ) )
except:
print "Error: unable to start thread"
def UpdateHost(function,opcode):
# Sends data to the server
script_path = "https://www.privateeyepi.com/alarmhostr.php?u="+globals.user+"&p="+globals.password+"&function="+str(function)
i=0
for x in opcode:
script_path=script_path+"&opcode"+str(i)+"="+str(opcode[i])
i=i+1
if globals.PrintToScreen: print "Host Update: "+script_path
try:
rt=urllib2.urlopen(script_path)
except urllib2.HTTPError:
if globals.PrintToScreen: print "HTTP Error"
return False
time.sleep(.2)
temp=rt.read()
if globals.PrintToScreen: print temp
l = find_all(temp,"/n");
RecordSet = temp.split(',')
c=[]
y=0
c.append([])
for x in RecordSet:
if x=="/n":
y=y+1
if y < l:
c.append([])
else:
if isNumber(x):
c[y].append(int(x))
else:
c[y].append(x)
rt=ProcessActions(c)
if rt==False:
return(False)
else:
return(c)
def ProcessActions(ActionList):
FalseInd=True
for x in ActionList:
if x[0]=="/EMAIL":
SendEmailAlertFromRule(x[1], x[2],0)
x.remove
if x[0]=="/SEMAIL":
SendEmailAlert(x[1])
x.remove
if x[0]=="/CHIME":
StartChimeThread()
x.remove
if x[0]=="/rn588":
exit()
if x[0]=="/FALSE":
FalseInd=False
if x[0]=="/SIREN":
StartSirenThread(x[2])
x.remove
if x[0]=="/PHOTO":
SendEmailAlertFromRule(x[1], x[2],1)
x.remove
if x[0]=="/RELAYON":
SwitchRelay(1)
x.remove
if x[0]=="/RELAYOFF":
SwitchRelay(0)
x.remove
if x[0]=="/WRELAYON":
SwitchRFRelay(1)
x.remove
if x[0]=="/WRELAYOFF":
SwitchRFRelay(0)
x.remove
return(FalseInd)
def StartSirenThread(Zone):
try:
thread.start_new_thread(Siren, (Zone, ) )
except:
print "Error: unable to start thread"
def SwitchRelay(onoff):
GPIO.setmode(GPIO.BOARD)
GPIO.setup(globals.RelayPin, GPIO.OUT)
GPIO.output(globals.RelayPin,onoff)
def SwitchRFRelay(onoff):
# declare to variables, holding the com port we wish to talk to and the speed
port = '/dev/ttyAMA0'
baud = 9600
# open a serial connection using the variables above
ser = serial.Serial(port=port, baudrate=baud)
# wait for a moment before doing anything else
sleep(0.2)
for i in range(0,3):
if (onoff==True):
ser.write('a{}RELAYAON-'.format(globals.WRelayPin))
else:
ser.write('a{}RELAYAOFF'.format(globals.WRelayPin))
time.sleep(2)
ser.close
def SendToLCD(GPIOnumber, Location, status):
import paho.mqtt.client as paho
if status==0:
ActionStr="_"
topic="alarm_activity"
else:
if status==1:
ActionStr="_"
topic="alarm_activity"
else:
topic="temperature"
if status==2:
ActionStr=str(GPIOnumber)+","+Location
else:
ActionStr="Undefined"
#client = mosquitto.Mosquitto('privateeyepi')
client = paho.Client()
client.connect(globals.lcd_ip)
if status <= 1:
if globals.PrintToScreen:
print str(Location)+"**"+str(ActionStr)
client.publish(topic, str(Location)+"**"+str(ActionStr))
else:
if globals.PrintToScreen:
print str(ActionStr)
client.publish(topic, ActionStr)
client.disconnect()
def Siren(Zone):
GPIO.setmode(GPIO.BOARD)
if globals.UseSiren == True:
GPIO.setup(globals.SirenGPIOPin, GPIO.OUT) #Siren pin setup
else:
return
if globals.SirenDelay>0:
globals.SirenStartTime = time.time()
while time.time() < globals.SirenStartTime + globals.SirenDelay:
if globals.BeepDuringDelay:
GPIO.output(globals.SirenGPIOPin,True)
time.sleep(1)
GPIO.output(globals.SirenGPIOPin,False)
time.sleep(4)
GPIO.output(globals.SirenGPIOPin,True)
globals.SirenStartTime = time.time()
if globals.PrintToScreen: print "Siren Activated"
while time.time() < globals.SirenStartTime + globals.SirenTimeout:
time.sleep(5)
if CheckForSirenDeactivation(Zone) == True:
break
GPIO.output(globals.SirenGPIOPin,False)
if globals.PrintToScreen: print "Siren Deactivated"
def CheckForSirenDeactivation(Zone):
# Routine to fetch the location and zone descriptions from the server
RecordSet = GetDataFromHost(16,[Zone])
if globals.PrintToScreen: print RecordSet
ZoneStatus=RecordSet[0][0]
if ZoneStatus=="FALSE":
return (True)
def StartChimeThread():
try:
thread.start_new_thread(SoundChime, ())
except:
print "Error: unable to start thread"
def SoundChime():
if globals.ChimeDuration>0:
GPIO.setmode(GPIO.BOARD)
GPIO.setup(globals.ChimeGPIOPin, GPIO.OUT) #Siren pin setup
GPIO.output(globals.ChimeGPIOPin,True)
time.sleep(globals.ChimeDuration)
GPIO.output(globals.ChimeGPIOPin,False)
def GetDataFromHost(function,opcode):
# Request data and receive reply (request/reply) from the server
script_path = "https://www.privateeyepi.com/alarmhostr.php?u="+globals.user+"&p="+globals.password+"&function="+str(function)
i=0
for x in opcode:
script_path=script_path+"&opcode"+str(i)+"="+str(opcode[i])
i=i+1
if globals.PrintToScreen: print script_path
try:
rt = urllib2.urlopen(script_path)
except urllib2.HTTPError:
return False
temp=rt.read()
if globals.PrintToScreen: print temp
l = find_all(temp,"/n");
RecordSet = temp.split(',')
c=[]
y=0
c.append([])
for x in RecordSet:
if x=="/n":
y=y+1
if y < l:
c.append([])
else:
if isNumber(x):
c[y].append(int(x))
else:
c[y].append(x)
rt=ProcessActions(c)
if rt==False:
return(False)
else:
return(c)
return(c)
def BuildMessage(SensorNumber):
# Routine to fetch the location and zone descriptions from the server
RecordSet = GetDataFromHost(6,[SensorNumber])
if globals.PrintToScreen: print RecordSet
if RecordSet==False:
return
zonedesc=RecordSet[0][0]
locationdesc = RecordSet[0][1]
messagestr="This is an automated email from your house alarm system. Alarm activated for Zone: "+zonedesc+" ("+locationdesc+")"
return messagestr
def BuildMessageFromRule(SensorNumber, smartruleid):
RecordSet = GetDataFromHost(7,[smartruleid, SensorNumber])
if RecordSet==False:
return
numrows = len(RecordSet)
messagestr="This is an automated email from PrivateEyePi. Rule triggered for Zone(s): "+RecordSet[0][3]+", Location: "+RecordSet[0][4]+" and for rule "
for i in range(0,numrows,1):
if RecordSet[i][0]==1:
messagestr=messagestr+"Alarm Activated"
if RecordSet[i][0]==2:
messagestr=messagestr+"Alarm Deactivated"
if RecordSet[i][0]==3:
messagestr=messagestr+"Circuit Open"
if RecordSet[i][0]==4:
messagestr=messagestr+"Circuit Closed"
if RecordSet[i][0]==5:
messagestr=messagestr+"Open for " + str(RecordSet[i][1]) + " Minutes"
if RecordSet[i][0]==6:
messagestr=messagestr+"Closed for " + str(RecordSet[i][1]) + " Minutes"
if RecordSet[i][0]==7:
messagestr=messagestr+"Where sensor value (" + str(RecordSet[i][5]) + ") is between " + str(RecordSet[i][1]) + " " + str(RecordSet[i][2])
if RecordSet[i][0]==8:
messagestr=messagestr+"Tamper"
if RecordSet[i][0]==9:
messagestr=messagestr+"Day Of Week is between " + str(RecordSet[i][1]) + " and " + str(RecordSet[i][2])
if RecordSet[i][0]==10:
messagestr=messagestr+"Hour Of Day is between " + str(RecordSet[i][1]) + " and " + str(RecordSet[i][2])
if RecordSet[i][0]==11:
messagestr=messagestr+"Where secondary sensor value (" + str(RecordSet[i][6]) + ") is between " + str(RecordSet[i][1]) + " " + str(RecordSet[i][2])
if i<numrows-1:
messagestr=messagestr + " AND "
return messagestr
def SendEmailAlertFromRule(ruleid, SensorNumber, photo):
try:
thread.start_new_thread(SendEmailAlertThread, (SensorNumber, ruleid, True, photo, ) )
except:
print "Error: unable to start thread"
def SendEmailAlert(SensorNumber):
try:
thread.start_new_thread(SendEmailAlertThread, (SensorNumber,0 , False, False) )
except:
print "Error: unable to start thread"
def SendEmailAlertThread(SensorNumber, smartruleid, ruleind, photo):
# Get the email addresses that you configured on the server
RecordSet = GetDataFromHost(5,[0])
if RecordSet==False:
return
numrows = len(RecordSet)
if globals.smtp_server=="":
return
if ruleind:
msgtext = BuildMessageFromRule(SensorNumber, smartruleid)
else:
msgtext = BuildMessage(SensorNumber)
for i in range(numrows):
# Define email addresses to use
addr_to = RecordSet[i][0]
addr_from = globals.smtp_user #Or change to another valid email recognized under your account by your ISP
# Construct email
if (photo==1):
files = 0
files = glob.glob(globals.photopath)
latestphoto = get_latest_photo(files)
msg = MIMEMultipart()
else:
msg = MIMEText(msgtext)
msg['To'] = addr_to
msg['From'] = addr_from
msg['Subject'] = 'Alarm Notification' #Configure to whatever subject line you want
#attach photo
if (photo==1):
msg.preamble = 'Multipart message.\n'
part = MIMEText(msgtext)
msg.attach(part)
part = MIMEApplication(open(latestphoto,"rb").read())
part.add_header('Content-Disposition', 'attachment', filename=latestphoto)
msg.attach(part)
# Send the message via an SMTP server
#Option 1 - No Encryption
if globals.email_type==1:
s = smtplib.SMTP(globals.smtp_server)
elif globals.email_type==2:
#Option 2 - SSL
s = smtplib.SMTP_SSL(globals.smtp_server, 465)
elif globals.email_type==3:
#Option 3 - TLS
s = smtplib.SMTP(globals.smtp_server,587)
s.ehlo()
s.starttls()
s.ehlo()
else:
s = smtplib.SMTP(globals.smtp_server)
s.login(globals.smtp_user,globals.smtp_pass)
s.sendmail(addr_from, addr_to, msg.as_string())
s.quit()
if globals.PrintToScreen: print msg;
def SendCustomEmail(msgText, msgSubject):
# Get the email addresses that you configured on the server
RecordSet = GetDataFromHost(5,[0])
if RecordSet==False:
return
numrows = len(RecordSet)
if globals.smtp_server=="":
return
for i in range(numrows):
# Define email addresses to use
addr_to = RecordSet[i][0]
addr_from = globals.smtp_user #Or change to another valid email recognized under your account by your ISP
# Construct email
msg = MIMEText(msgText)
msg['To'] = addr_to
msg['From'] = addr_from
msg['Subject'] = msgSubject #Configure to whatever subject line you want
# Send the message via an SMTP server
#Option 1 - No Encryption
if globals.email_type==1:
s = smtplib.SMTP(globals.smtp_server)
elif globals.email_type==2:
#Option 2 - SSL
s = smtplib.SMTP_SSL(globals.smtp_server, 465)
elif globals.email_type==3:
#Option 3 - TLS
s = smtplib.SMTP(globals.smtp_server,587)
s.ehlo()
s.starttls()
s.ehlo()
else:
s = smtplib.SMTP(globals.smtp_server)
s.login(globals.smtp_user,globals.smtp_pass)
s.sendmail(addr_from, addr_to, msg.as_string())
s.quit()
if globals.PrintToScreen: print msg;
Your lcd.py module doesn't define any functions (or other top-level objects) named noDisplay or message, only a class named CharLCD and a function named DisplayLCD. So, when you try to import something that doesn't exist, of course you get an ImportError.
It's true that the CharLCD class has methods named noDisplay and message, but that doesn't mean you can just import them as top-level functions. (And, even if you could, you can't call them that way; you need a CharLCD object to call its methods.)
I suspect you need to read a basic tutorial on classes, like the Classes chapter in the official tutorial.
Meanwhile, I think the code you want is:
from lcd import CharLCD
# ...
char_lcd = CharLCD()
char_lcd.message("test with message")
time.sleep(5)
char_lcd.noDisplay()
(Also note the () in the last line. You need those parentheses to call a function or method; without them, you're just referring to the function or method itself, as a value, which has no more effect than just writing 2 on a line by itself.)