plant_monitor.py 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. from machine import ADC, Pin, SD, Timer
  2. import os
  3. import utime
  4. # Thresholds for the sensors
  5. LOWER_THRESHOLD = 500
  6. UPPER_THRESHOLD = 2500
  7. UPDATE_FREQ = 120 # seconds
  8. # File name for the data
  9. SENSOR_DATA = "plant_data.csv"
  10. # Format the time (epoch) for a better view
  11. def _format_time(tm_data):
  12. # Use a special shortcut to unpack tuple: *tm_data
  13. return "{0}-{1:0>2}-{2:0>2} {3:0>2}:{4:0>2}:{5:0>2}".format(*tm_data)
  14. class PlantMonitor:
  15. """
  16. This class reads soil moisture from one or more sensors and writes the
  17. data to a comma-separated value (csv) file as specified in the constructor.
  18. """
  19. # Initialization for the class (the constructor)
  20. def __init__(self, rtc):
  21. self.rtc = rtc
  22. # Try to access the SD card and make the new path
  23. try:
  24. sd = SD()
  25. os.mount(sd, '/sd')
  26. self.sensor_file = "/sd/{0}".format(SENSOR_DATA)
  27. print("INFO: Using SD card for data.")
  28. except:
  29. print("ERROR: cannot mount SD card, reverting to flash!")
  30. self.sensor_file = SENSOR_DATA
  31. print("Data filename = {0}".format(self.sensor_file))
  32. # Setup the dictionary for each soil moisture sensor
  33. adc = ADC(0)
  34. soil_moisture1 = {
  35. 'sensor': adc.channel(pin='P13', attn=3),
  36. 'power': Pin('P19', Pin.OUT),
  37. 'location': 'Green ceramic pot on top shelf',
  38. 'num': 1,
  39. }
  40. soil_moisture2 = {
  41. 'sensor': adc.channel(pin='P14', attn=3),
  42. 'power': Pin('P20', Pin.OUT),
  43. 'location': 'Fern on bottom shelf',
  44. 'num': 2,
  45. }
  46. # Setup a list for each sensor dictionary
  47. self.sensors = [soil_moisture1, soil_moisture2]
  48. # Setup the alarm to read the sensors
  49. a = Timer.Alarm(handler=self._read_sensors, s=UPDATE_FREQ,
  50. periodic=True)
  51. print("Plant Monitor class is ready...")
  52. # Clear the log
  53. def clear_log(self):
  54. log_file = open(self.sensor_file, 'w')
  55. log_file.close()
  56. # Get the filename we're using after the check for SD card
  57. def get_filename(self):
  58. return self.sensor_file
  59. # Read the sensor 10 times and average the values read
  60. def _get_value(self, sensor, power):
  61. total = 0
  62. # Turn power on
  63. power.value(1)
  64. for i in range (0,10):
  65. # Wait for sensor to power on and settle
  66. utime.sleep(5)
  67. # Read the value
  68. value = sensor.value()
  69. total += value
  70. # Turn sensor off
  71. power.value(0)
  72. return int(total/10)
  73. # Monitor the sensors, read the values and save them
  74. def _read_sensors(self, line):
  75. log_file = open(self.sensor_file, 'a')
  76. for sensor in self.sensors:
  77. # Read the data from the sensor and convert the value
  78. value = self._get_value(sensor['sensor'], sensor['power'])
  79. print("Value read: {0}".format(value))
  80. time_data = self.rtc.now()
  81. # datetime,num,value,enum,location
  82. log_file.write(
  83. "{0},{1},{2},{3},{4}\n".format(_format_time(time_data),
  84. sensor['num'], value,
  85. self._convert_value(value),
  86. sensor['location']))
  87. log_file.close()
  88. # Convert the raw sensor value to an enumeration
  89. def _convert_value(self, value):
  90. # If value is less than lower threshold, soil is dry else if it is greater than upper threshold, it is wet, else all is well.
  91. if (value <= LOWER_THRESHOLD):
  92. return "dry"
  93. elif (value >= UPPER_THRESHOLD):
  94. return "wet"
  95. return "ok"