sds.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # SDS011_Feinstaub_Sensor.py
  5. #
  6. # Copyright 2017 by luetzel <webmaster_at_raspberryblog.de>
  7. #
  8. # This program is free software; you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation; either version 2 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License
  19. # along with this program; if not, write to the Free Software
  20. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  21. # MA 02110-1301, USA.
  22. #
  23. #
  24. from __future__ import print_function
  25. import serial, struct, sys, time
  26. import socket,json,requests
  27. ser = serial.Serial()
  28. #ser.port = sys.argv[1]
  29. ser.port = "/dev/serial/by-id/usb-1a86_USB2.0-Serial-if00-port0"
  30. #ser.port = "/dev/ttyUSB5"
  31. ser.baudrate = 9600
  32. sensebox_id="5cf8a49707460b001b43a245"
  33. sensebox_25="5cf8a49707460b001b43a247"
  34. sensebox_10="5cfc0d44a1ba9f001a6e57ae"
  35. url="https://ingress.opensensemap.org/boxes/%s/%s"
  36. pm=[0,0]
  37. pm_count=0
  38. ser.open()
  39. ser.flushInput()
  40. def dump_data(d):
  41. print(' '.join(x.encode('hex') for x in d))
  42. def process_frame(d):
  43. #dump_data(d) #debug
  44. r = struct.unpack('<HHxxBBB', d[2:])
  45. pm25 = r[0]/10.0
  46. pm10 = r[1]/10.0
  47. print(pm25)
  48. checksum = sum(ord(v) for v in d[2:8])%256
  49. out=(0,0)
  50. if (checksum==r[2] and r[3]==0xab):
  51. out=(pm25,pm10)
  52. return out
  53. def export_data(pm25,pm10):
  54. print("PM 2.5: {} μg/m^3 PM 10: {} μg/m^3".format(pm25, pm10))
  55. r = requests.post(url % (sensebox_id,sensebox_25),json={'value': pm25})
  56. if r.status_code != requests.codes.ok:
  57. print("Error %d: %s" % (r.status_code,r.text))
  58. r = requests.post(url % (sensebox_id,sensebox_10),json={'value': pm10})
  59. if r.status_code != requests.codes.ok:
  60. print("Error %d: %s" % (r.status_code,r.text))
  61. json_out={"time": int(time.time()*1000),"device": "ragps","payload":{"pm25": int(pm25*1000),"pm10": int(pm10*1000)}}
  62. try:
  63. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  64. except:
  65. print("{}: could not connect to database".format(time.time()))
  66. else:
  67. s.connect(("banana", 24048))
  68. s.sendall(json.dumps(json_out))
  69. s.close()
  70. def sensor_read():
  71. byte = 0
  72. while byte != "\xaa":
  73. byte = ser.read(size=1)
  74. d = ser.read(size=10)
  75. out=(0,0)
  76. if d[0] == "\xc0":
  77. out=process_frame(byte + d)
  78. return out
  79. # 0xAA, 0xB4, 0x06, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x06, 0xAB
  80. def sensor_wake():
  81. bytes = ['\xaa', #head
  82. '\xb4', #command 1
  83. '\x06', #data byte 1
  84. '\x01', #data byte 2 (set mode)
  85. '\x01', #data byte 3 (sleep)
  86. '\x00', #data byte 4
  87. '\x00', #data byte 5
  88. '\x00', #data byte 6
  89. '\x00', #data byte 7
  90. '\x00', #data byte 8
  91. '\x00', #data byte 9
  92. '\x00', #data byte 10
  93. '\x00', #data byte 11
  94. '\x00', #data byte 12
  95. '\x00', #data byte 13
  96. '\xff', #data byte 14 (device id byte 1)
  97. '\xff', #data byte 15 (device id byte 2)
  98. '\x05', #checksum
  99. '\xab'] #tail
  100. for b in bytes:
  101. ser.write(b)
  102. # xAA, 0xB4, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x05, 0xAB
  103. def sensor_sleep():
  104. bytes = ['\xaa', #head
  105. '\xb4', #command 1
  106. '\x06', #data byte 1
  107. '\x01', #data byte 2 (set mode)
  108. '\x00', #data byte 3 (sleep)
  109. '\x00', #data byte 4
  110. '\x00', #data byte 5
  111. '\x00', #data byte 6
  112. '\x00', #data byte 7
  113. '\x00', #data byte 8
  114. '\x00', #data byte 9
  115. '\x00', #data byte 10
  116. '\x00', #data byte 11
  117. '\x00', #data byte 12
  118. '\x00', #data byte 13
  119. '\xff', #data byte 14 (device id byte 1)
  120. '\xff', #data byte 15 (device id byte 2)
  121. '\x05', #checksum
  122. '\xab'] #tail
  123. for b in bytes:
  124. ser.write(b)
  125. def main(args):
  126. a = 2
  127. while a > 1:
  128. sensor_wake()
  129. time.sleep(30)
  130. ser.flushInput()
  131. pm25=0
  132. pm10=0
  133. pm_count=0
  134. for n in range(5):
  135. pm_data=sensor_read()
  136. if(pm_data[0]>0):
  137. pm25=pm25+pm_data[0]
  138. pm10=pm10+pm_data[1]
  139. pm_count=pm_count+1
  140. time.sleep(2)
  141. export_data(round(pm25/pm_count,1),round(pm10/pm_count,1))
  142. # sensor_sleep()
  143. time.sleep(600)
  144. if __name__ == '__main__':
  145. import sys
  146. sys.exit(main(sys.argv))