Workbackup

This commit is contained in:
2017-11-14 07:39:49 +01:00
parent 8c444c32e5
commit c51b755024
5 changed files with 574 additions and 0 deletions

118
ADED.py Normal file
View File

@@ -0,0 +1,118 @@
from time import time, strftime
from DB import *
entities = {}
"""
Entity 880022
Gemelkerfassung
"""
#NR, ART, ITEM, NAME, TYPE, LEN, RESOLUTION, UNIT, CODE
entities ['880022'] = [
(1, 'KEY', '900080', 'Rind-ID', 'N', 15, 0, '', 0),
(2, 'MAN', '800004', 'Betrieb Nr', 'N', 15, 0, '', 0),
(3, 'MAN', '800043', 'Betriebstaette (AE)', 'N', 2, 0, '', 0),
(4, 'OPT', '900045', 'Name', 'AN', 24, 0, '', 0),
(5, 'KEY', '900054', 'Datum (Melken)', 'N', 8, 0, 'CCYYMMDD', 0),
(6, 'KEY', '900078', 'Startzeit (Melken)', 'N', 6, 0, 'hhmmss', 0),
(7, 'OPT', '900042', 'Milchmenge im Gemelk', 'N', 3, 1, 'KG', 0),
(8, 'OPT', '900024', 'Kastennummer', 'N', 6, 0, '', 0),
(9, 'OPT', '900025', 'Flaschennummer', 'N', 4, 0, '', 0),
(10, 'OPT', '800700', 'Barcode', 'N', 10, 0, '', 0),
(11, 'OPT', '800701', 'gemolken', 'N', 1, 0, '', 8889),
(12, 'OPT', '800703', 'Melkereignis', 'AN', 3, 0, '', 999),
(13, 'OPT', '800702', 'Zwischenmelkzeit', 'N', 6, 0, '', 0),
(14, 'OPT', '900070', 'Stallnummer', 'N', 15, 0, '', 0),
(15, 'OPT', '804841', 'Bemerkungen', 'AN', 30, 0, '', 0),
(16, 'OPT', '800134', 'RFID', 'AN', 20, 0, '', 0),
(17, 'OPT', '821005', 'Milchflussdauer', 'N', 5, 3, '', 0),
(18, 'OPT', '900097', 'Herdenspez. Elektron. ID', 'AN', 16, 9, '', 0)
]
class ADIS:
def __init__ (self, db, loglevel):
self.db = db
self.loglevel = loglevel
#Optional Fields for an entity
self.entityfields = {'880022': ['800702', '900070']}
def log (self, msg, _level = 3):
"""
Logfile
Loglevel 9 = print to console
"""
if self.loglevel == 9:
print (msg)
if _level <= self.loglevel:
file = open ("/var/log/lactor/" + os.getcwd().split('/')[-1] + '.err', "a")
dt = datetime.now ()
file.write ("%4d-%02d-%02d %02d:%02d:%02d.%06d: " %(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond) + msg + "\n")
file.close ()
def parsedn (self, data):
"parse an DN and returen datasetdefinition"
entityid = data [: 6]
_data = data [8:]
entity = entities [entityid]
ds = []
for i in range (0, len (_data) , 11):
_item = _data [i: i + 6]
_len = int (_data [i + 6: i + 8])
_unit = _data [i + 8: i + 9]
print _item
for nr, art, item, name, datatype, length, resolution, unit, code in entity:
if _item == item:
ds.append ((nr, art, item, name, datatype, length, resolution, unit, code))
if _len != length:
print ("Error Size was %d instead of %d" % (_len, length))
print (ds)
def createmilkdataset (self, animalinfo):
"""
Creating entity for 880022
"""
animalnr, earmark, rfid, status = animalinfo
data = {'900070': animalnr,
'900080': earmark,
'800143': rfid
}
md = self.db.getlastmilkdatabyanimal (animalnr, 1)
if len (md):
ts, animalnr, ammount, time = md [0]
dt = datetime.strptime (ts, '%Y-%m-%d %H:%M:%S')
mdate = dt.strftime ('%Y%m%d')
mtime = dt.strftime ('%H%M%S')
data ['900054'] = mdate
data ['900078'] = mtime
data ['900042'] = ammount
ds = "VN880022"
for nr, art, item, name, datatype, length, resolution, unit, code in entities ['880022']:
if art == 'KEY' or item in self.entityfields ['880022']:
self.log ("Item %s needed" % item, 9)
if item in data:
if datatype == 'AN':
ds += data[item].rjust (int (length + 1))
elif datatype == 'N':
ds += "%d".rjust (int (length + 1)) % (int (data[item]) * 10**int (resolution))
self.log (ds, 9)
return ds
def testmilkdataset (self):
animalinfo = self.db.getanimal ('711')
self.createmilkdataset (animalinfo [0])
if __name__ == "__main__":
adis = ADIS (DB ('/opt/data/animaldb.sqlite', '/tmp/talog.sql', logtest, errlogtest), loglevel = 9)
adis.testmilkdataset ()
#parsedn ('88002200800004150009000801500080002910000900054080009000780600090004203100800701010008000430200080070303000900070060')

184
DB.py Normal file
View File

@@ -0,0 +1,184 @@
#!/opt/local/bin/python3.0
import sqlite3 as sqlite
from sys import exit
from datetime import datetime
import os, shutil
def logtest (level, msg):
print (msg)
def errlogtest (msg):
print (msg)
def connectdb (dbfile):
"""
Create connection to database
return DB Object
user gets information if failure
"""
print ("Verbindung zu %s herstellen" %dbfile)
try:
db = sqlite.connect (dbfile, check_same_thread=False)
return db
except:
print ("Konnte DB Verbindung nicht herstellen")
exit (1)
class DB:
# Database Stuff
# --------------
def __init__ (self, dbfile, talogfile, log, errlog):
self.db = connectdb (dbfile)
self.talogfile = talogfile
self.log = log
self.errlog = errlog
def executesql (self, dbstring, arguments = ()):
"""
Fuehre den uebergebenen SQL-Befehl aus und liefere ein Cursor-Objekt
zurueck.
"""
try:
cursor = self.db.cursor ()
cursor.execute (dbstring, arguments)
except sqlite.Error as e:
print ("An error occurred:", e.args[0])
raise Warning
except OperationalError: #, msg:
print ("Datenbankausfuehrung fehlgeschlagen. Ausgeloest durch: " + dbstring)
raise Warning
except IntegrityError: #, msg:
print ("Doppelter Eintrag. Ausgeloest durch: " + dbstring)
raise Warning
except ProgrammingError: #, msg:
print ("Fehlerhaftes SQL. Ausgeloest durch: " + dbstring)
raise Warning
except Warning: #, msg:
pass
#Build Transaction Log
if (dbstring.find ('DELETE') >= 0) or\
(dbstring.find ('INSERT') >= 0) or\
(dbstring.find ('UPDATE') >= 0):
file = open (self.talogfile, "a")
dt = datetime.now ()
file.write ("%4d-%02d-%02d %02d:%02d:%02d.%06d: " %(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond))
file.write (dbstring + ";\n")
file.close ()
self.db.commit ()
return cursor
# Tierddaten allgemein
#------------------
def getanimals (self):
"""
Return all Data of animals
"""
try:
cursor = self.executesql ("SELECT animalnr, earmark, rfid, forbidmilk FROM animals;")
except:
return None
res = cursor.fetchall ()
return res
def addanimal (self, data):
"""
Add animal
"""
try:
cursor = self.executesql ("INSERT OR REPLACE INTO animals (animalnr, earmark, rfid, forbidmilk ) VALUES ('%(animalnr)d', '%(earmark)s', '%(rfid)s', '%(forbidmilk)s');" % data)
except:
print ("Couldnt insert into animals")
raise Warning
def getanimal (self, animalnr):
"""
Get Animaldata
"""
try:
cursor = self.executesql ("SELECT animalnr, earmark, rfid, forbidmilk FROM animals WHERE animalnr = '%s';" % animalnr)
except:
print ("Couldnt read from animals")
return cursor.fetchall ()
def addmilkdata (self, data):
"""
Add Milkingdata
"""
try:
cursor = self.executesql ("INSERT INTO milkdata (ts, animalnr, ammount, time) VALUES ('%(ts)s', '%(animalnr)d', '%(ammount)s', '%(time)s');" % data)
except:
print ("Couldnt insert into milkdata")
raise Warning
def updatemilkdata (self, data):
"""
Add Milkingdata
"""
try:
print ("UPDATE milkdata SET ammount = '%(ammount)s', time = '%(time)s' WHERE ts='%(ts)s' AND animalnr = '%(animalnr)d';" % data)
cursor = self.executesql ("UPDATE milkdata SET ammount = '%(ammount)s', time = '%(time)s' WHERE ts='%(ts)s' AND animalnr = '%(animalnr)d';" % data)
except:
print ("Couldnt update milkdata")
raise Warning
def getallmilkdata (self):
"""
Return all Milkingdata
"""
try:
cursor = self.executesql ("SELECT * FROM milkdata;")
except:
return None
res = cursor.fetchall ()
return res
def getlastmilkdatabyanimal (self, animalnr, last = 1):
"""
Return Milkingdata of Animal
"""
try:
cursor = self.executesql ("SELECT ts, animalnr, ammount, time FROM milkdata WHERE animalnr = '%d' ORDER BY ts DESC LIMIT %d;" % (int (animalnr), last))
except:
return None
res = cursor.fetchall ()
return res
if __name__ == "__main__":
conn = DB ('/opt/data/animaldb.sqlite', '/tmp/talog.sql', logtest, errlogtest)
data = {'animalnr' : 711,
'earmark' : 'DE09 4711',
'rfid' : '123543546',
'forbidmilk': '0'}
#conn.addanimal (data)
print (conn.getanimals ())
data = {'animalnr' : 711,
'ts' : '2017.03.01 14:24:57',
'ammount' : '5.00',
'time' : '234'}
#conn.addmilkdata (data)
print (conn.getlastmilkdatabyanimal ('711', 3))
print ("All Milkingdata")
for ds in conn.getiallmilkdata ():
print (ds)

13
initdata/dblayout.sql Normal file
View File

@@ -0,0 +1,13 @@
CREATE TABLE animals (
animalnr INTEGER UNIQUE NOT NULL,
earmark CHAR (25) NOT NULL,
rfid INTEGER,
forbidmilk CHAR (1) default '0'
);
CREATE TABLE milkdata (
ts timestamp (14) NOT NULL,
animalnr INTEGER NOT NULL,
ammount decimal(10,2) NOT NULL default '0',
time integer NOT NULL
);

245
lactor.py Normal file
View File

@@ -0,0 +1,245 @@
import can
from DB import *
from time import sleep, time, strftime
from datetime import *
bus = None
infotype = {0 : 'S-Buffer deleted',
1 : 'Reserved 1',
2 : 'command',
3 : 'milking time',
4 : 'animal nr',
5 : 'milkammount',
6 : 'state'
}
class CanListener (can.Listener):
def on_message_received (self, msg):
print ("Received Data")
self.CanDecode (msg)
def set_db (self, dbpath = '/opt/lactor/animaldb.sqlite'):
self.db_con = DB (dbpath, '/tmp/talog.sql', logtest, errlogtest)
self.dataset = [None] * 128
self.waitack = [0] * 128
self.waitackst = [0] * 128
self.loglevel = 9
#[arbitration_id', 'data', 'dlc', 'id_type', 'is_error_frame', 'is_extended_id', 'is_remote_frame', 'timestamp']
#<class 'can.message.Message'>
#Timestamp: 1499861978.530813 ID: 0581 000 DLC: 8 20 20 20 20 30 30 30 30
def log (self, msg, _level = 3):
"""
Logfile
Loglevel 9 = print to console
"""
if self.loglevel == 9:
print (msg)
if _level <= self.loglevel:
file = open ("/var/log/lactor/" + os.getcwd().split('/')[-1] + '.err', "a")
dt = datetime.now ()
file.write ("%4d-%02d-%02d %02d:%02d:%02d.%06d: " %(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond) + msg + "\n")
file.close ()
def CanDecode (self, msg):
"""
Decoding Can Telegram
"""
if msg.is_extended_id:
self.log ("Rcvd Msg with Extended ID", 0)
return
if msg.is_error_frame:
self.log ("Rcvd Msg Error Frame", 0)
return
if msg.is_remote_frame:
self.log ("Rcvd Msg Remote Frame", 0)
return
_id = msg.arbitration_id
self.log ("Msg %s" % msg, 9)
#Pos 11 Direction
if not is_set (_id, 10):
self.log ("Received Data to xLactor", 0)
return
#Pos 8-10 Infotype
_info_type = (_id & 0b01110000000) >> 7
self.log ("Infotype: %s %s" % (hex (_id), infotype [_info_type]), 3)
#Pos 1-7 Address
_address = (_id & 0b00001111111)
self.log ("Address: %d" % _address, 4)
#Determine Addresstype
if ((_address & 0b1000000) == 0b0000000):
self.log ("Terminal %d" % _address, 3)
elif ((_address & 0b1110000) == 0b1000000):
#Obsolete
self.log ("Gatecontrol %d" % _address, 3)
elif ((_address & 0b1110000) == 0b1010000):
#Obsolete
self.log ("Animalrecognition %d" % _address, 3)
elif ((_address & 0b1110000) == 0b1100000):
#Obsolete
self.log ("WateringPlace %d" & _address, 3)
elif ((_address & 0b1110000) == 0b1110000):
#Obsolete
self.log ("Other %d" % _address, 1)
_data = msg.data
_repdata = None
_sendecho = 1
#Animalnr request
if infotype [_info_type] == 'animal nr':
if 'REQ' in str (_data):
self.log ("Requested AnimalNr from Recognition", 3)
#FixMe AnimalNr from rFID
animalnr = 12
#_sendecho = 0
_repdata = bytearray (('REP00%03d' % animalnr).encode ())
self.waitack [_address] = 1
elif self.waitack [_address]:
self.log ("Received Echo", 3)
self.waitack [_address] = 0
_sendecho = 0
else:
self.log ("New Milking Data", 3)
_animalnr = int (_data)
if _animalnr:
if self.dataset [_address]:
self.log ("A Milkingdataset already esists %s" % self.dataset [_address])
self.dataset [_address] = {'animalnr' : _animalnr,
'ts' : strftime ("%Y-%m-%d %H:%M:%S"),
'ammount' : 0}
else:
self.dataset [_address] = None
self.log ("AnimalNr is 0 ignore Milkingdata")
#State requeset
elif infotype [_info_type] == 'state':
_sendecho = 0 #No Echo on State telegram
if self.waitackst [_address]:
self.log ("Received Echo for Status", 3)
self.waitackst [_address] = 0
_sendecho = 0
else:
animalnr = int (_data)
self.log ("Statusrequest for animal %d" % animalnr)
animalinfo = self.db_con.getanimal (animalnr)
_ammountestimated = 12
if len (animalinfo):
_aianimalnr, _aiearmark, _airfid, _aiforbidmilk = animalinfo[0]
if _aiforbidmilk != '0':
self.log ("Milking is forbidden %s" % _aiforbidmilk, 1)
_repdata = bytearray ('GESP '.encode ())
self.waitackst [_address] = 1
else:
self.log ("Animal is Ok check milking data", 1)
_lastmilkdata = self.db_con.getlastmilkdatabyanimal (animalnr, 1)
if len (_lastmilkdata):
_mdts, _mdanimalnr, _mdammount, _mdtime = _lastmilkdata [0]
_mddt = datetime.strptime (_mdts, '%Y-%m-%d %H:%M:%S')
_lmdelta = (datetime.now() - _mddt).seconds
self.log ("Delta to Last Milking was %s s" % _lmdelta, 5)
if (_lmdelta < 7200):
self.log ("2nd Milking", 1)
_repdata = bytearray ('2MEL '.encode ())
self.waitackst [_address] = 1
else:
self.log ("All Ok", 5)
_repdata = bytearray ((' OK%04d' % int (_ammountestimated)).encode ())
self.waitackst [_address] = 1
else:
self.log ("All Ok", 5)
_repdata = bytearray ((' OK%04d' % int (_ammountestimated)).encode ())
self.waitackst [_address] = 1
else:
self.log ("Animal not in DB", 1)
_repdata = bytearray ('UNBE '.encode ())
self.waitackst [_address] = 1
elif infotype [_info_type] == 'milkammount':
if self.dataset [_address]:
self.dataset [_address] ['ammount'] = int (_data)
else:
self.log ("Dataset empty ignoring Milking ammount", 1)
elif infotype [_info_type] == 'milking time':
if self.dataset [_address]:
self.log ("Milking Time for existing Dataset %s" % self.dataset [_address])
self.dataset [_address] ['time'] = int (_data)
animalinfo = self.db_con.getanimal (self.dataset [_address]['animalnr'])
if len (animalinfo):
self.log ("Found animal in DB", 5)
else:
self.log ("Animal %d not found in animaldb create" % (self.dataset [_address]['animalnr']), 1)
#FixMe Check Animal Nr Range + x
_animaldata = {'animalnr' : self.dataset [_address]['animalnr'],
'earmark' : '2730000000000000',
'rfid' : '',
'forbidmilk' : '0'}
self.db_con.addanimal (_animaldata)
self.log ("Check last milking data", 1)
_lastmilkdata = self.db_con.getlastmilkdatabyanimal (self.dataset [_address]['animalnr'], 1)
if len (_lastmilkdata):
_mdts, _mdanimalnr, _mdammount, _mdtime = _lastmilkdata [0]
_mddt = datetime.strptime (_mdts, '%Y-%m-%d %H:%M:%S')
_lmdelta = (datetime.now() - _mddt).seconds
self.log ("Delta to Last Milking was %s s" % _lmdelta, 5)
if _lmdelta < 7200:
self.log ("2nd Milking", 1)
self.log ("Adding Ammount Old %d New %d, Time Old %d New %d" % ( self.dataset [_address] ['ammount'], int (_mdammount), self.dataset [_address] ['time'],int (_mdtime)), 5)
self.dataset [_address] ['ts'] = _mdts
self.dataset [_address] ['ammount'] = self.dataset [_address] ['ammount'] + int (_mdammount)
self.dataset [_address] ['time'] = self.dataset [_address] ['time'] + int (_mdtime)
self.db_con.updatemilkdata (self.dataset [_address])
else:
self.log ("All Ok", 5)
self.db_con.addmilkdata (self.dataset [_address])
else:
self.log ("All Ok", 5)
self.db_con.addmilkdata (self.dataset [_address])
self.dataset [_address] = None
else:
self.log ("Dataset empty ignoring Milking time", 1)
self.log ("ID %s" % hex (_id), 5)
self.log ("data %s" % _data, 5)
self.log ("Reply", 9)
self.log ("==========", 9)
#Preparing Acktelegram
if _sendecho:
nmsg = can.Message (arbitration_id = int (_id & 0b01111111111), data =_data, extended_id = False)
bus.send(nmsg)
self.log (str (nmsg), 9)
if _repdata:
nmsg = can.Message (arbitration_id = int (_id & 0b01111111111), data =_repdata, extended_id = False)
bus.send(nmsg)
self.log (str (nmsg), 9)
def is_set (x, n):
"""
Check if Bit i Set 0 ....
"""
return x & 2**n != 0
if __name__ == "__main__":
bus = can.interface.Bus (channel='can0', bustype='socketcan_native')
a_listener = CanListener ()
a_listener.set_db (dbpath = '/opt/data/animaldb.sqlite')
notifier = can.Notifier (bus, [a_listener])
try:
while True:
sleep (1)
except KeyboardInterrupt:
bus.shutdown ()

14
sampledata/ADIDxxx.txt Normal file
View File

@@ -0,0 +1,14 @@
DH990001000000000800090000208000900003080009000040600090000624000900009080
VH990001DD: 0000199720140505123259BouMatic Milkrobot ADR2003
DN88000100800004150009000320800080013801000800140010
VN880001 312700120140503ER
DN88002200800004150009000801500090007015000900045240009000540800090007806000900042031009000240600090002504000800703030
VN880022 3127001276000353230784 1Erna
20140408145657150?????????? 0
VN880022 3127001276000353230784 1Erna
20140409063305214?????????? 0
VN880022 3127001276000353230784 1Erna
20140409164758177?????????? 0
VN880022 3127001276000353230784 1Erna
20140410062551197?????????? 0