Reader module handling inventory and recording.

This commit is contained in:
Mikaël Ates 2016-03-09 16:04:03 +01:00
parent 71d1e49074
commit a57bdd0b36
1 changed files with 419 additions and 0 deletions

419
rfiddriver.py Normal file
View File

@ -0,0 +1,419 @@
# -*- coding: utf-8 -*-
'''
Copyright (C) 2016 Entr'ouvert
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
'''
import os
import time
import json
import logging
import serial
import csv
from datetime import datetime
from datetime import date, timedelta
from time import sleep
import whisper
import librfid
import epc
import config
import logging_conf
import utils
logger = logging.getLogger(__name__)
MAX_RETRY = 3
METRICS = ['temperature', 'heartrate']
def try_command(reader, command):
retry = 0
while retry < MAX_RETRY:
try:
response = reader.device.send(command)
return response
except Exception, e:
logger.warning("Reader request failed with error '{}'".format(e))
retry += 1
logger.debug("Remaining tries : {}".format(MAX_RETRY - retry))
logger.error("Command failed")
return False
def get_health_parameters(reader):
logger.debug('Get_HealthParameters')
quality = ['Disconnected', 'Bad', 'Good']
command = librfid.ReaderCommand(command_name='Get_HealthParameters',
reader=reader.device)
response = try_command(reader, command)
if not response:
return False
health_parameters = response.data
logger.debug("health_parameters : '{}'".format(health_parameters))
antennas = []
for i in range(4):
tune = "Tune{}".format(i)
if health_parameters[tune][1] >= 1:
antennas.append(i)
logger.debug("Antenna {} connection quality : {} ({})".format(i,
quality[health_parameters[tune][1]], health_parameters[tune][0]))
logger.debug("{} antennas connected : '{}'".format(len(antennas), antennas))
logger.debug("Reader core temperature: %d" % health_parameters['TempCore'])
logger.debug("Reader power amplificator temperature: %d" % health_parameters['PA'])
reader.config.set_setting('antenna_connected', antennas)
return True
def get_rf_settings(reader):
logger.debug('Get_RFSettings')
command = librfid.ReaderCommand(command_name='Get_RFSettings',
reader=reader.device)
response = try_command(reader, command)
if not response:
return False
i = 0
for logic_port in response.data:
if logic_port['ScanDelay'] or logic_port['PowerAnt']:
logger.debug("Logic port: %s" % i)
logger.debug("\tScanDelay: %s ms" % logic_port['ScanDelay'])
logger.debug("\tPowerAnt: %s dBm" % logic_port['PowerAnt'])
logger.debug("\tAntNb: %s" % logic_port['AntNb'])
i += 1
return True
def set_rf_settings(reader, logic_ports):
logger.debug('Set_RFSettings')
logger.debug("Logic ports configuration : '{}'".format(logic_ports))
command = librfid.ReaderCommand(command_name='Set_RFSettings',
reader=reader.device, data=logic_ports)
response = try_command(reader, command)
if not response:
return False
return True
class Reader:
def __init__(self, *args, **kwargs):
logger.debug('Reader initialization.')
self.config = config.Config()
for metric in METRICS:
fn = "{}.wsp".format(metric)
setattr(self, "fn_{}".format(metric), fn)
logger.debug('Metric {} : filename {}.'.format(metric, fn))
if not os.path.isfile(fn):
logger.debug('Creating file.')
whisper.create(fn, [(1, 2592000)])
else:
logger.debug('Existing file.')
self.csv_temperature = "temperature.csv"
logger.debug('Metric temperature : filename {}.'.format(self.csv_temperature))
if not os.path.isfile(self.csv_temperature):
logger.debug('Creating file {}.'.format(self.csv_temperature))
with open(fn, 'w') as f:
writer = csv.writer(f, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
row = ["date", "time", "int", "degree", "volt"]
writer.writerow(row)
else:
logger.debug('Existing file.')
self.csv_heartrate = "heartrate.csv"
logger.debug('Metric heartrate : filename {}.'.format(self.csv_heartrate))
if not os.path.isfile(self.csv_heartrate):
logger.debug('Creating file {}.'.format(self.csv_heartrate))
with open(fn, 'w') as f:
writer = csv.writer(f, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
row = ["date", "time", "hr1 int", "hr1 second", "hr1 bpm", "hr2 int", "hr2 second",
"hr2 bpm", "hr3 int", "hr3 second", "hr3 bpm"]
writer.writerow(row)
else:
logger.debug('Existing file.')
self.csv_epc = 'epc.csv'
if not os.path.isfile(self.csv_epc):
logger.debug('Creating file.')
with open(self.csv_epc, 'w') as f:
writer = csv.writer(f, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
row = ["date", "time", "epc", "trcal", "can_precision", "sensor_sensibility",
"sensor_center", "temperature_int", "temperature_degree", "temperature_volt",
"tension_int", "tension_volt", "cpt_trcal", "period_osc", "hr1_int",
"hr1_second", "hr1_bpm", "hr2_int", "hr2_second", "hr2_bpm", "hr3_int",
"hr3_second", "hr3_bpm"]
writer.writerow(row)
else:
logger.debug('Existing file epc.csv.')
self.config.set_setting('exit_reader', False)
self.device = librfid.models.RFIDReader()
def now(self):
return int(utils.unix_time(datetime.utcnow()))
def write_metric_value(self, metric, value):
logger.debug('Update {} with value {}.'.format(metric, value))
whisper.update(getattr(self, "fn_{}".format(metric)), value)
def write_metric_value_csv(self, metric, values):
with open(getattr(self, "csv_{}".format(metric)), 'a') as f:
writer = csv.writer(f, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
now = datetime.now()
for value in values:
row = [
now.strftime("%Y/%m/%d"),
now.strftime("%H:%M:%S"),
]
row.extend(value)
logger.debug('Update csv {} with values {}.'.format(metric, row))
writer.writerow(row)
def write_epc_csv(self, epcs):
with open(self.csv_epc, 'a') as f:
writer = csv.writer(f, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
now = datetime.now()
for epc in epcs:
row = [
now.strftime("%Y/%m/%d"),
now.strftime("%H:%M:%S"),
epc.epc,
epc.trcal,
epc.can_precision,
epc.sensor_sensibility,
epc.sensor_center,
epc.temperature_int,
epc.temperature_degree,
epc.temperature_volt,
epc.tension_int,
epc.tension_volt,
epc.cpt_trcal,
epc.period_osc,
epc.hr1_int,
epc.hr1_second,
epc.hr1_bpm,
epc.hr2_int,
epc.hr2_second,
epc.hr2_bpm,
epc.hr3_int,
epc.hr3_second,
epc.hr3_bpm,
]
logger.debug('Update csv {} with values {}.'.format(self.csv_epc, row))
writer.writerow(row)
def device_ready(self):
(exit_reader,
pause_reader,
self.reader_sleep_short,
self.temperature,
self.heartrate) = self.config.reader_config()
logger.debug('Reader configuration : exit_reader {} - pause_reader {} '
'- reader_sleep_short {} - temperature {} - heartrate {}'
''.format(exit_reader, pause_reader, self.reader_sleep_short,
self.temperature, self.heartrate))
if exit_reader:
logger.info('Exit reader asked.')
exit(0)
if pause_reader:
logger.debug('Reader off.')
logger.debug('Sleep {}ms.'.format(self.reader_sleep_short))
self.config.set_setting('reader_ready', False)
return False
logger.debug('Reader on.')
try:
self.device.get_connection()
logger.debug('Device connected')
self.config.set_setting('reader_ready', True)
return True
except serial.serialutil.SerialException, e:
self.config.set_setting('reader_ready', False)
logger.debug('Device not connected : {}.'.format(e))
return False
def device_check(self):
while not self.device_ready():
logger.debug('Sleep {}ms.'.format(self.reader_sleep_short))
sleep(self.reader_sleep_short)
if not get_health_parameters(self):
logger.error('Command get_health_parameters failed, stop tag detection')
return False
return True
def inventory(self,
delay=100,
power=31,
logic_port=None,
skip_device_check=False,
skip_config=False,
silent=True,
epcs_csv=False,
metrics_csv=False,
metrics_db=False):
if not skip_device_check:
if not self.device_check():
return None
if not skip_config:
logic_ports = []
if logic_port is not None:
logic_ports = [{'ScanDelay': 0, 'PowerAnt': 0, 'AntNb': antenna}
for antenna in self.config.get_setting('antenna_connected')]
logic_ports[logic_port] = {
'ScanDelay': delay,
'PowerAnt': power,
'AntNb': self.config.get_setting('antenna_connected')[logic_port]
}
else:
logic_ports = [{'ScanDelay': delay, 'PowerAnt': power, 'AntNb': antenna}
for antenna in self.config.get_setting('antenna_connected')]
if not set_rf_settings(self, logic_ports):
logger.error('Command set_rf_settings failed, stop tag detection')
return None
if not get_rf_settings(self):
logger.error('Command get_rf_settings failed, stop tag detection')
return None
logger.debug('Inventory')
command = librfid.Command(command_name='Inventory')
response = try_command(self, command)
if not response:
logger.error('Command Inventory failed')
return None
if response.data:
for tag in response.data:
logger.debug("Tag: %s" % tag['EPC'].encode('hex'))
logger.debug("\t Read on logic port {} be antenna {}".format(tag['AntID'],
self.config.get_setting('antenna_connected')[tag['AntID']]))
logger.debug("\t Times read on all logic ports: %s" % tag['NbRead'])
epc_decoded = epc.VeadistaEPC(str(tag['EPC'].encode('hex')))
logger.debug("\n{}".format(epc_decoded))
if epcs_csv:
epcs = [epc.VeadistaEPC(tag['EPC'].encode('hex')) for tag in response.data]
self.write_epc_csv(epcs)
if metrics_csv:
temperatures = []
hrs = []
for tag in response.data:
e = epc.VeadistaEPC(tag['EPC'].encode('hex'))
if self.temperature:
temperatures.append((e.temperature_int,
e.temperature_degree,
e.temperature_volt))
if self.heartrate:
hrs.append((e.hr1_int, e.hr1_second, e.hr1_bpm, e.hr2_int, e.hr2_second,
e.hr2_bpm, e.hr3_int, e.hr3_second, e.hr3_bpm))
if self.temperature:
logger.debug("Temperature vector : '{}'".format(temperatures))
self.write_metric_value_csv('temperature', temperatures)
if self.heartrate:
logger.debug("Heartrate vector : '{}'".format(hrs))
self.write_metric_value_csv('heartrate', hrs)
if metrics_db:
if len(response.data) > 0 and self.temperature:
e = epc.VeadistaEPC(response.data[0]['EPC'].encode('hex'))
if e.temperature_degree:
self.write_metric_value('temperature', e.temperature_degree)
if len(response.data) > 1 and self.heartrate:
e = epc.VeadistaEPC(response.data[1]['EPC'].encode('hex'))
if e.hr1_bpm:
self.write_metric_value('heartrate', e.hr1_bpm)
if not silent:
print "\a"
return response
def detection(self,
delay=100,
power=31,
logic_port=None,
silent=True):
if not self.device_check():
return None
"""
As many logic ports as antenna, set all in fast inventory
"""
logic_ports = [{'ScanDelay': delay, 'PowerAnt': power, 'AntNb': antenna}
for antenna in self.config.get_setting('antenna_connected')]
if not set_rf_settings(self, logic_ports):
logger.error('Command set_rf_settings failed, stop tag detection')
return None
if not get_rf_settings(self):
logger.error('Command get_rf_settings failed, stop tag detection')
return None
while(True):
while not self.device_ready():
logger.debug('Sleep {}ms.'.format(self.reader_sleep_short))
sleep(self.reader_sleep_short)
response = self.inventory(delay=delay, power=power, logic_port=logic_port,
skip_device_check=True, silent=silent)
if not response:
logger.error('Command Inventory failed, stop tag detection')
return None
if response.data:
# Veadista assumption is only one physical tag that may return mutiple EPC.
# So if response.data it is enough to look at the first epc to know the logic port
logger.info("Tag in the field of logic_port {}".format(response.data[0]['AntID']))
ant_id = self.config.get_setting('antenna_connected')[response.data[0]['AntID']]
self.config.set_setting('tag_in_field', ant_id)
return response.data[0]['AntID']
else:
logger.debug('No tag detected')
self.config.set_setting('tag_in_field', '')
logger.debug('Sleep {}ms.'.format(self.reader_sleep_short))
sleep(self.reader_sleep_short)
def read(self,
power=31,
logic_port=None,
silent=True,
epcs_csv=False,
metrics_csv=False,
metrics_db=False):
logger.debug('Entering reading function.')
detection = True if logic_port is None else False
logger.debug('Tag detection : {}.'.format(detection))
while(True):
if detection:
logic_port = self.detection(power=power, silent=silent)
logger.info('The tag is in the field of logic_port {}.'.format(logic_port))
if logic_port is None:
logger.error('The tag detection failed.')
break
reader_sleep_long = self.config.get_setting('reader_sleep_long')
logger.debug('Sleep {} s.'.format(reader_sleep_long))
sleep(reader_sleep_long)
self.inventory(delay=4000, power=power, logic_port=logic_port, silent=silent,
epcs_csv=epcs_csv, metrics_csv=metrics_csv, metrics_db=metrics_db)