piufared 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. #!/usr/bin/python3
  2. #
  3. # Copyright (c) 2021 Clementine Computing LLC.
  4. #
  5. # This file is part of PopuFare.
  6. #
  7. # PopuFare is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU Affero General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # PopuFare is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU Affero General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU Affero General Public License
  18. # along with PopuFare. If not, see <https://www.gnu.org/licenses/>.
  19. #
  20. import serial
  21. import re
  22. import math
  23. import time
  24. import sys
  25. import os
  26. from datetime import datetime
  27. PIU_FARED_VERSION = "0.1.0"
  28. cur_t = int(time.time())
  29. opt = {
  30. "verbose" : 2,
  31. "state_fn" : "/home/bus/config/piufared.state",
  32. "sleepy" : 0.015625,
  33. "ratelimit_mark" : 0.0,
  34. "ratelimit_t" : 10.0,
  35. "dev" : "/dev/ttyPIU",
  36. "baud" : 115200,
  37. "serial_timeout" : 0.05,
  38. "MAX_BUF" : 1024,
  39. "mag_fn" : "/home/bus/log/credential.mag",
  40. "rfid_fn" : "/home/bus/log/credential.rfid",
  41. "qr_fn" : "/home/bus/log/credential.barcode",
  42. "mag_ts" : cur_t,
  43. "rfid_ts" : cur_t,
  44. "qr_ts" : cur_t
  45. }
  46. def _DT():
  47. return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  48. def write_state(_opt):
  49. with open(opt["state_fn"], "w") as ofp:
  50. ofp.write("mag_ts " + str(_opt["mag_ts"]) + "\nrfid_ts " + str(_opt["rfid_ts"]) + "\nqr_ts " + str(_opt["qr_ts"]) + "\n")
  51. def read_state(_opt):
  52. with open(_opt["state_fn"]) as fp:
  53. lines = fp.read().split("\n")
  54. for line in lines:
  55. tok = line.split(" ")
  56. if len(tok) < 2: continue
  57. if tok[0] == "mag_ts":
  58. _opt["mag_ts"] = int(tok[1])
  59. elif tok[0] == "rfid_ts":
  60. _opt["rfid_ts"] = int(tok[1])
  61. elif tok[0] == "qr_ts":
  62. _opt["qr_ts"] = int(tok[1])
  63. def send_data(_ser, _s):
  64. #_s = dat + "\r\n"
  65. _ser.write(_s.encode("utf-8"))
  66. # if we don't have a state file, create a new
  67. # one with the default (0) values
  68. #
  69. if not os.path.isfile(opt["state_fn"]):
  70. write_state(opt)
  71. read_state(opt)
  72. piu_serial = serial.Serial(opt["dev"], baudrate=opt["baud"], timeout=opt["serial_timeout"])
  73. #_msg = '/M:;255100010014851?\r\n'
  74. #piu_serial.write(_msg.encode('utf-8'))
  75. sys.stdout.flush()
  76. buf = []
  77. while True:
  78. eol = False
  79. read_len = -1
  80. have_data = False
  81. while (len(buf) < opt["MAX_BUF"]) and (not eol) and (read_len != 0):
  82. b = piu_serial.read()
  83. read_len = len(b)
  84. for _b in b:
  85. if _b == ord('\r') or _b == ord('\n'):
  86. eol = True
  87. have_data = True
  88. break
  89. else:
  90. buf.append(chr(_b))
  91. if len(buf) >= opt["MAX_BUF"]:
  92. have_data = True
  93. if have_data:
  94. s = "".join(buf)
  95. buf = []
  96. if len(s)==0:
  97. if time.time() > opt["ratelimit_mark"]:
  98. ## DEBUG
  99. if opt["verbose"] > 0:
  100. print(_DT(), "[piufared]", "sending init msg '/?: ?=rider_ui\\r\\n")
  101. os.stdout.flush()
  102. write_data(piu_serial, "/?: ?=rider_ui\r\n")
  103. opt["ratelimit_mark"] = time.time() + opt["ratelimit_t"]
  104. continue
  105. if len(s) < 3: continue
  106. if s[0] != '/': continue
  107. if s[2] != ':': continue
  108. msg = s[3:]
  109. if s[1] == '0':
  110. os.system("/home/bus/bin/piumsg 'relay passenger_message " + msg + "'")
  111. elif s[1] == '1':
  112. os.system("/home/bus/bin/piumsg 'relay passenger_notify " + msg + "'")
  113. ###
  114. state_change = False
  115. with open(opt["mag_fn"]) as fp:
  116. lines = fp.read().split("\n")
  117. for idx in range(len(lines)-1):
  118. line = lines[idx]
  119. tok = line.split(" ")
  120. if len(tok)!=2: continue
  121. _ts = int(tok[0].split(":")[0])
  122. if _ts <= opt["mag_ts"]: continue
  123. if opt["verbose"] > 0:
  124. print(_DT(), "[piufared]", "sending mag", " ".join(tok[1:]))
  125. send_data(piu_serial, "/M:" + " ".join(tok[1:]) + "\r\n")
  126. opt["mag_ts"] = _ts
  127. state_change = True
  128. with open(opt["rfid_fn"]) as fp:
  129. lines = fp.read().split("\n")
  130. for idx in range(len(lines)-1):
  131. line = lines[idx]
  132. tok = line.split(" ")
  133. if len(tok)!=2: continue
  134. _ts = int(tok[0].split(":")[0])
  135. if _ts <= opt["rfid_ts"]: continue
  136. if opt["verbose"] > 0:
  137. print(_DT(), "[piufared]", "sending rfid", " ".join(tok[1:]))
  138. send_data(piu_serial, "/R:" + " ".join(tok[1:]) + "\r\n")
  139. opt["rfid_ts"] = _ts
  140. state_change = True
  141. with open(opt["qr_fn"]) as fp:
  142. lines = fp.read().split("\n")
  143. for idx in range(len(lines)-1):
  144. line = lines[idx]
  145. tok = line.split(" ")
  146. if len(tok)!=2: continue
  147. _ts = int(tok[0].split(":")[0])
  148. if _ts <= opt["qr_ts"]: continue
  149. if opt["verbose"] > 0:
  150. print(_DT(), "[piufared]", "sending qr", " ".join(tok[1:]))
  151. send_data(piu_serial, "/M:" + " ".join(tok[1:]) + "\r\n")
  152. opt["qr_ts"] = _ts
  153. state_change = True
  154. if state_change:
  155. if opt["verbose"] > 1:
  156. print(_DT(), "[piufared]", "state change, writing")
  157. write_state(opt)
  158. time.sleep(opt["sleepy"])