Json 多线程问题?

Json multithreading issue?

提问人:xampL 提问时间:8/10/2023 最后编辑:xampL 更新时间:8/10/2023 访问量:53

问:

我非常不熟悉使用JSON文件来存储信息,并且收到一个错误,说明我在调试时遇到问题。在某些情况下,这是一个树莓派温室项目,我正在尝试使用 json 文件来存储数据,以便在我打开和关闭系统时存储数据。这是我不断收到的错误:

>>> Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python3.9/threading.py", line 954, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.9/threading.py", line 892, in run
    self._target(*self._args, **self._kwargs)
  File "/home/ben6brewer/Desktop/Greenhouse/GreenHouse.py", line 214, in lcd_updater
    self.lcd_display.screen2(self.get_minutes_elapsed())
  File "/home/ben6brewer/Desktop/Greenhouse/GreenHouse.py", line 227, in get_minutes_elapsed
    data = json.load(json_file)
  File "/usr/lib/python3.9/json/__init__.py", line 293, in load
    return loads(fp.read(),
  File "/usr/lib/python3.9/json/__init__.py", line 346, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python3.9/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python3.9/json/decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 35 column 5 (char 532)

以下是我的主要温室课程:

import time
import threading
from datetime import datetime
import RPi.GPIO as GPIO
import Adafruit_DHT
from LCD import LCDDisplay
from CreateGraph import GraphGenerator
from SendEmail import EmailSender
from time import sleep
from LCD import LCDScreens
import sys
import select
import json
import os

class GreenhouseController:
    def __init__(self):
        self.relay_pins = [24, 25]
        self.fan_pin = self.relay_pins[0]
        self.mist_pin = self.relay_pins[1]
        self.lowest_temp = 65 # degrees F
        self.highest_temp = 80 # degrees F
        self.lowest_humidity = 80 # %
        self.highest_humidity = 90 # %
        self.graph_generator = GraphGenerator() # Instantiate the GraphGenerator class
        self.email_sender = EmailSender()
        self.lcd_display = LCDDisplay(controller=self)
        self.minute_temperature_data = []
        self.minute_humidity_data = []
        self.hour_temperature_data = []
        self.hour_humidity_data = []

        self.current_second = int(time.time() % 60)
        self.last_second = None

        self.current_minute = int(time.time() // 60) % 60
        self.last_minute = None
        self.program_start_minute = int(time.time() // 60) % 60

        self.current_hour = int(time.time() // 3600) % 24
        self.last_hour = None
        self.program_start_hour = int(time.time() // 3600) % 24

        self.relative_count = 0
        self.system_activated = False

        self.humidity = 0
        self.temperature = 0
        # Get the absolute path to the current script's directory
        # path to json = '/home/ben6brewer/Desktop/Greenhouse/data.json'


        # Set up GPIO pins
        GPIO.setmode(GPIO.BCM)
        GPIO.setwarnings(False)
        GPIO.setup(self.fan_pin, GPIO.OUT)
        GPIO.setup(self.mist_pin, GPIO.OUT)

    def main(self):
        try:
            self.run_lcd()
            while True:
                self.check_user_input()
                if self.first_iteration_check():
                    self.send_boot_message()

                self.update_time()
                self.update_variables()
                # TRUE every 1 minute
                if self.minute_check():
                    self.minute_operations()

                    # True every 10 minutes:
                    if self.ten_minute_check():
                        self.ten_minute_operations()

                        # TRUE every 1 HOUR
                        if self.hour_check():
                            self.hour_operations()

                            # TRUE every 1 day
                            if self.day_check():
                                self.day_operations()

                self.system_activated = False
                if self.humidity_check():
                    self.activate_humidity()

                if self.temperature_check():
                    self.activate_fans()

                if self.system_activated == False:
                    sleep(2)

        except KeyboardInterrupt:
            pass

        GPIO.cleanup()

    @staticmethod
    def get_current_temperature():
        return round((Adafruit_DHT.read_retry(22, 4)[1]) * 9/5 + 32, 2)

    @staticmethod
    def get_current_humidity():
        return round(Adafruit_DHT.read_retry(22, 4)[0], 2)

    # Turns pump on for parameterized seconds
    def pump_on(self, seconds):
        GPIO.output(self.mist_pin, 0)
        sleep(seconds)
        GPIO.output(self.mist_pin, 1)
        self.add_to_total_pump_time(seconds)
        if self.get_total_pump_time() > 60:
            self.email_sender.send_pump_warning(self.get_total_pump_time())
            self.reset_total_pump_time()


    # Turns pump on for parameterized seconds
    def fans_on(self, seconds):
        GPIO.output(self.fan_pin, 0)
        sleep(seconds)
        GPIO.output(self.fan_pin, 1)

    def get_days_elapsed(self):
        return round(self.get_minutes_elapsed() / 1440, 2)

    def update_time(self):
        self.current_second = int(time.time() % 60)
        self.current_minute = int(time.time() // 60) % 60
        self.current_hour = int(time.time() // 3600) % 24

    def update_variables(self):
        self.humidity = self.get_current_humidity()
        self.temperature = self.get_current_temperature()

    def minute_check(self):
        return (self.last_minute is None or self.last_minute != self.current_minute)

    def minute_operations(self):
        self.last_minute = self.current_minute
        self.append_temperature_to_minute_array(self.temperature)
        self.append_humidity_to_minute_array(self.humidity)
        self.update_minutes_in_json(1)

    def ten_minute_check(self):
        return ((self.program_start_minute % 10) == (self.current_minute % 10))

    def ten_minute_operations(self):
        self.fans_on(45)
        sleep(45)

    def first_iteration_check(self):
        return (self.relative_count == 0)

    def send_boot_message(self):
        self.email_sender.send_boot_email(self.get_days_elapsed())

    def hour_check(self):
        return ((self.program_start_minute) == (self.current_minute))

    def hour_operations(self):
        average_temperature = round((sum(self.get_temperature_minute_array())) / len(self.get_temperature_minute_array()), 2)
        self.append_temperature_to_hour_array(average_temperature)

        average_humidity = round((sum(self.get_humidity_minute_array())) / len(self.get_humidity_minute_array()), 2)
        self.append_humidity_to_hour_array(average_humidity)

        self.reset_minute_arrays()
        self.relative_count += 1

    def day_check(self):
        minutes_elapsed = self.get_minutes_elapsed()
        return (minutes_elapsed >= 1440 and minutes_elapsed % 1440 == 0 and self.relative_count > 1)

    def day_operations(self):
        self.graph_generator.create_graph(self.get_days_elapsed(), [self.get_temperature_hour_array(), self.get_humidity_hour_array()])
        self.email_sender.send_email(self.get_days_elapsed())
        self.reset_hour_arrays()

    def humidity_check(self):
        return (self.humidity <= self.lowest_humidity)

    def activate_humidity(self):
        if self.get_current_humidity() < (self.lowest_humidity - 20):
            self.pump_on(30)
        elif self.get_current_humidity() < (self.lowest_humidity - 10):
            self.pump_on(20)
        else:
            self.pump_on(5)
        sleep(10)
        self.system_activated = True

    def temperature_check(self):
        return (self.temperature >= self.highest_temp or self.humidity >= self.highest_humidity)

    def activate_fans(self):
        if self.get_current_humidity() > self.highest_humidity:
            self.fans_on(20)
        elif self.get_current_temperature() > (self.highest_temp):
            self.fans_on(20)
        else:
            self.fans_on(10)
        self.system_activated = True

    def lcd_updater(self):
        current_screen = LCDScreens.SCREEN1

        while True:
            if current_screen == LCDScreens.SCREEN1:
                self.lcd_display.screen1(self.get_current_temperature(), self.get_current_humidity())

            elif current_screen == LCDScreens.SCREEN2:
                self.lcd_display.screen2(self.get_minutes_elapsed())

            # Switch to the next screen
            current_screen = LCDScreens.SCREEN1 if current_screen == LCDScreens.SCREEN2 else current_screen + 1
            sleep(5) # Adjust the delay time as needed (in seconds)

    def run_lcd(self):
        self.lcd_thread = threading.Thread(target=self.lcd_updater)
        self.lcd_thread.daemon = True
        self.lcd_thread.start()

    def get_minutes_elapsed(self):
        with open('/home/ben6brewer/Desktop/Greenhouse/data.json', 'r') as json_file:
            data = json.load(json_file)
            minutes_elapsed = data.get('minutes', 0)
            return minutes_elapsed




    def update_minutes_in_json(self, minutes_to_add):
        with open('/home/ben6brewer/Desktop/Greenhouse/data.json', 'r+') as json_file:
            data = json.load(json_file)
            current_minutes = data.get('minutes', 0)
            new_minutes = current_minutes + minutes_to_add
            data['minutes'] = new_minutes
            json_file.seek(0)
            json.dump(data, json_file, indent=4)
            json_file.truncate()

    def reset_json_data(self):
        data = {
        "minutes": 0,
        "TotalPumpTime": 0,
        "TemperatureMinuteArray": [],
        "HumidityMinuteArray": [],
        "TemperatureHourArray": [],
        "HumidityHourArray": []
        }

        with open('/home/ben6brewer/Desktop/Greenhouse/data.json', 'w') as json_file:
            json.dump(data, json_file, indent=4)

    def append_temperature_to_minute_array(self, temperature):
        with open('/home/ben6brewer/Desktop/Greenhouse/data.json', 'r+') as json_file:
            data = json.load(json_file)
            temperature_array = data.get('TemperatureMinuteArray', [])
            temperature_array.append(temperature)
            data['TemperatureMinuteArray'] = temperature_array
            json_file.seek(0)
            json.dump(data, json_file, indent=4)
            json_file.truncate()

    def append_humidity_to_minute_array(self, humidity):
        with open('/home/ben6brewer/Desktop/Greenhouse/data.json','r+') as json_file:
            data = json.load(json_file)
            humidity_array = data.get('HumidityMinuteArray', [])
            humidity_array.append(humidity)
            data['HumidityMinuteArray'] = humidity_array
            json_file.seek(0)
            json.dump(data, json_file, indent=4)
            json_file.truncate()

    def append_temperature_to_hour_array(self, temperature):
        with open('/home/ben6brewer/Desktop/Greenhouse/data.json', 'r+') as json_file:
            data = json.load(json_file)
            temperature_array = data.get('TemperatureHourArray', [])
            temperature_array.append(temperature)
            data['TemperatureHourArray'] = temperature_array
            json_file.seek(0)
            json.dump(data, json_file, indent=4)
            json_file.truncate()

    def append_humidity_to_hour_array(self, humidity):
        with open('/home/ben6brewer/Desktop/Greenhouse/data.json', 'r+') as json_file:
            data = json.load(json_file)
            humidity_array = data.get('HumidityHourArray', [])
            humidity_array.append(humidity)
            data['HumidityHourArray'] = humidity_array
            json_file.seek(0)
            json.dump(data, json_file, indent=4)
            json_file.truncate()

    def reset_minute_arrays(self):
        with open('/home/ben6brewer/Desktop/Greenhouse/data.json', 'r+') as json_file:
            data = json.load(json_file)
            data['TemperatureMinuteArray'] = []
            data['HumidityMinuteArray'] = []
            json_file.seek(0)
            json.dump(data, json_file, indent=4)
            json_file.truncate()

    def reset_hour_arrays(self):
        with open('/home/ben6brewer/Desktop/Greenhouse/data.json', 'r+') as json_file:
            data = json.load(json_file)
            data['TemperatureHourArray'] = []
            data['HumidityHourArray'] = []
            json_file.seek(0)
            json.dump(data, json_file, indent=4)
            json_file.truncate()

    def get_temperature_minute_array(self):
        with open('/home/ben6brewer/Desktop/Greenhouse/data.json', 'r') as json_file:
            data = json.load(json_file)
            temperature_array = data.get('TemperatureMinuteArray', [])
            return temperature_array

    def get_humidity_minute_array(self):
        with open('/home/ben6brewer/Desktop/Greenhouse/data.json', 'r') as json_file:
            data = json.load(json_file)
            humidity_array = data.get('HumidityMinuteArray', [])
            return humidity_array

    def get_temperature_hour_array(self):
        with open('/home/ben6brewer/Desktop/Greenhouse/data.json', 'r') as json_file:
            data = json.load(json_file)
            temperature_array = data.get('TemperatureHourArray', [])
            return temperature_array

    def get_humidity_hour_array(self):
        with open('/home/ben6brewer/Desktop/Greenhouse/data.json', 'r') as json_file:
            data = json.load(json_file)
            humidity_array = data.get('HumidityHourArray', [])
            return humidity_array

    def add_to_total_pump_time(self, pump_time):
        with open('/home/ben6brewer/Desktop/Greenhouse/data.json', 'r+') as json_file:
            data = json.load(json_file)
            total_pump_time = data.get('TotalPumpTime', 0)
            total_pump_time += pump_time
            data['TotalPumpTime'] = total_pump_time
            json_file.seek(0)
            json.dump(data, json_file, indent=4)
            json_file.truncate()
    def get_total_pump_time(self):
        with open('/home/ben6brewer/Desktop/Greenhouse/data.json', 'r') as json_file:
            data = json.load(json_file)
            total_pump_time = data.get('TotalPumpTime', 0)
            return total_pump_time

    def reset_total_pump_time(self):
        with open('/home/ben6brewer/Desktop/Greenhouse/data.json', 'r+') as json_file:
            data = json.load(json_file)
            data['TotalPumpTime'] = 0
            json_file.seek(0)
            json.dump(data, json_file, indent=4)
            json_file.truncate()

    def check_user_input(self):
        rlist, _, _ = select.select([sys.stdin], [], [], 0.1)

        if rlist:
            user_input = sys.stdin.readline().strip()
            if user_input:
                words = user_input.split()
                val = None
                if words[-1].isdigit():
                    val = int(words.pop())
                    command = ' '.join(words)
                    if command == 'read vars':
                        print('temperature: ' + str(self.get_current_temperature()) + ' F')
                        print('humidity: ' + str(self.get_current_humidity()) + ' %')
                    elif command == 'get time':
                        weeks = self.get_minutes_elapsed() // 10080 # 10080 minutes = 7 days (1 week)
                        remaining_minutes = self.get_minutes_elapsed() % 10080
                        days = remaining_minutes // 1440 # 1440 minutes = 1 day
                        remaining_minutes %= 1440
                        hours = remaining_minutes // 60 # 60 minutes = 1 hour
                        minutes = remaining_minutes % 60
                        print(f'Week: {weeks}, Day: {days}, Hour: {hours}, Minute: {minutes}')
                    elif command == 'stall':
                        print('sleeping for ' + str(val) + ' seconds')
                        sleep(val)
                        self.update_minutes_in_json(val//60)
                        print('done sleeping')
                    elif command == 'pump on':
                        GPIO.output(self.mist_pin, 0)
                        print('pump on for ' + str(val) + ' seconds')
                        sleep(val)
                        GPIO.output(self.mist_pin, 1)
                        print('pump off')
                    elif command == 'fans on':
                        GPIO.output(self.fan_pin, 0)
                        print('fans on for ' + str(val) + ' seconds')
                        sleep(val)
                        GPIO.output(self.fan_pin, 1)
                        print('fans off')
                    elif command == 'pump off':
                        GPIO.output(self.mist_pin, 1)
                        print('pump off')
                    elif command == 'fans off':
                        GPIO.output(self.fan_pin, 1)
                        print('fans off')
                    elif command == 'set lowest humidity':
                        print('setting lowest humidity to ' + str(val) + '%')
                        self.lowest_humidity = val
                        print('updated self.lowest_humidity')
                    elif command == 'set highest humidity':
                        print('setting highest humidity to ' + str(val) + '%')
                        self.highest_humidity = val
                        print('updated self.highest_humidity')
                    elif command == 'set lowest temperature':
                        print('setting lowest temp to ' + str(val) + 'F')
                        self.lowest_temp = val
                        print('updated self.lowest_temp')
                    elif command == 'set highest temperature':
                        print('setting highest temp to ' + str(val) + 'F')
                        self.highest_temp = val
                        print('updated self.highest_temp')
                    elif command == 'AGT preset':
                        self.lowest_temp = 63
                        self.highest_temp = 80
                        self.lowest_humidity = 80
                        self.highest_humidity = 90
                        print(f'temp range: {self.lowest_temp}-{self.highest_temp}, humidity range {self.lowest_humidity}-{self.highest_humidity}')
                        print('Reset Minutes.txt to 0')
                        self.reset_json_data()
                    elif command == 'SG preset':
                        self.lowest_temp = 60
                        self.highest_temp = 80
                        self.lowest_humidity = 40
                        self.highest_humidity = 55
                        print(f'temp range: {self.lowest_temp}-{self.highest_temp}, humidity range {self.lowest_humidity}-{self.highest_humidity}')
                        print('Reset Minutes.txt to 0')
                        self.reset_json_data()
                    elif command == 'reset':
                        print('clearing data')
                        self.reset_json_data()
                        print('data cleared')
                    else:
                        print()
                        print('list valid requests:')
                        print()
                        print('GETTERS / SETTERS:')
                        print('get vars - gets temperature and humidity')
                        print('get time - gets current time statistics')
                        print('stall (seconds) - stalls for x amount of seconds')
                        print('set minutes (minutes) - set the minutes elapsed')
                        print('set lowest humidity (%) - updates self.lowest_humidity')
                        print('set highest humidity (%) - updates self.highest_humidity')
                        print('set lowest temperature (F) - updates self.lowest_temp')
                        print('set highest temperature (F) - updates self.highest_temp')
                        print()
                        print('HARDWARE CONTROLS:')
                        print('pump on (seconds) - turns humidifier on for x seconds')
                        print('fans on (seconds) - turns fans on for x seconds')
                        print('pump off - turns humidifier off')
                        print('fans off - turns fans off')
                        print()
                        print('PRESET GROWING CONDITIONS:')
                        print('AGT preset - ideal growing conditions for AGT')
                        print('SG preset - ideal growing conditions for Super Greens')
                        print()
                        print('SYSTEM RESET')
                        print('reset - clears the json storage file')

controller = GreenhouseController()
controller.main()

下面是 JSON:

{
    "minutes": 34079,
    "TotalPumpTime": 50,
    "TemperatureMinuteArray": [
        66.92,
        66.92,
        67.1,
        67.28,
        67.46,
        67.46,
        67.64,
        67.82,
        68.0,
        67.64,
        67.82,
        67.82
    ],
    "HumidityMinuteArray": [
        79.1,
        81.7,
        84.8,
        87.8,
        89.8,
        87.1,
        86.6,
        88.2,
        89.2,
        81.7,
        82.3,
        85.7
    ],
    "TemperatureHourArray": [
        69.08,
        68.44,
    ],
    "HumidityHourArray": [
        93.7,
        84.73,
    ]
}

我希望能够继续将数据存储在JSON中,我只是无法弄清楚这个错误是什么。

python json 多线程 验证 raspberry-pi

评论

4赞 Brian61354270 8/10/2023
JSON 文件中的第 35 行是什么?
4赞 Tim Roberts 8/10/2023
顺便说一句,你不应该让每个单独的函数都重写那个JSON。只需在 Python 数据结构中维护数据,然后使用“readdata”和“writedata”函数将其从文件复制/复制到文件即可。主线代码知道文件何时过时并需要更新。每当你发现自己写了 3 或 4 次相同的代码时,该代码就需要放在函数中。
2赞 Brian61354270 8/10/2023
@xampL 这绝对不是您的脚本在收到该错误时尝试解码的 JSON 内容。当它尝试解析第 35 行的第 5 个字符时,该错误发生,这也是整个文件中的第 532 个字符。其中少于 35 行,不到 500 个字符。
2赞 Brian61354270 8/10/2023
@xampL 不要在评论中添加新信息。注释是暂时的。相反,请通过编辑为您的问题添加任何新信息或澄清。
2赞 Brian61354270 8/10/2023
@xampL 该问题必须归因于您的文件包含无效的 JSON,因此确切的内容是相关的。我不知道它是否代表您的实际文件,但不是有效的 JSON 值。JSON 不允许尾随逗号。[ 69.08, ]

答: 暂无答案