Raspberry Pi로 기록되는 온도, 습도 등의 로그 회전

이게 뭐야



Raspberry Pi 4에서 기록중인 실온 등의 환경 데이터의 파일이 좀처럼 크기가되어 왔기 때문에
  • logging 기능을 사용하여 데이터 파일 회전
  • 데이터를 수집 할 기회가 증가 할 것으로 예상되므로 데이터 파일을 csv에서 json으로 마이그레이션

  • 하기로 결정했습니다.

    환경


  • Raspberry Pi 4
  • Linux raspi4 5.4.42-v8+ #1319 SMP PREEMPT Wed May 20 14:18:56 BST 2020 aarch64 GNU/Linux
  • 기압, 온도 및 습도 센서 (BME280)
  • Python 3.8.7 (default, Jan 27 2021, 11:28:25)

  • 작업 정책


  • 표준 logging와 json 포맷터는 여기를 사용한다
  • BME280의 코드는 Switch Science의 GitHub에서 빌린 것을 수정하여 사용한다.

  • BME280 설정



    Switch Science의 github에서 얻은 bme280_sample.py를 2to3을 사용하여 변환합니다.
    % 2to3-2.7 -w bme280_sample.py
    

    bme280.py에 복사하여 다음 수정
    $ diff bme280_sample.py bme280.py 
    69,71c69
    <       compensate_T(temp_raw)
    <       compensate_P(pres_raw)
    <       compensate_H(hum_raw)
    ---
    >       return compensate_T(temp_raw), compensate_P(pres_raw), compensate_H(hum_raw)
    95c93
    <       print("pressure : %7.2f hPa" % (pressure/100))
    ---
    >       return pressure/100
    103c101
    <       print("temp : %-6.2f ℃" % (temperature)) 
    ---
    >       return temperature
    117c115
    <       print("hum : %6.2f %" % (var_h))
    ---
    >       return var_h
    

    logging 설정에서 온도 등 읽기까지



    제대로 간다.
    먼저 thp_logger.py와 project_logging.py를 만듭니다.
  • bme280.py
  • project_logging.py

  • thp_logger.py로 가져오고 thp_logger.py를 실행합니다.

    thp_logger.py는 이런 식으로 만들었습니다.

    thp_logger.py
    #coding: utf-8
    import time
    import datetime
    import os
    
    import bme280
    
    import logging
    from project_logging import getLogger
    logger = getLogger(__name__)
    
    def main():
        mesuredData = []
        mesuredData = bme280.readData()
        logger.info({'timestamp':time.time(),'temp(deg.)': mesuredData[0],'pressure(hPa)':mesuredData[1],'humid.(%)':mesuredData[2]})
    
    if __name__ == '__main__':
        while True:
            main()
            time.sleep(1)
    

    time.sleep()은 원하는대로 부디.

    송어는 project_logging.py입니다.

    project_logging.py
    import logging
    import datetime
    from pytz import timezone
    from pythonjsonlogger import jsonlogger
    import logging.handlers
    
    now = datetime.datetime.now()
    filename = now.strftime("%Y%m%d") +'_thpLog.json'
    
    # https://github.com/madzak/python-json-logger#customizing-fields
    class JsonFormatter(jsonlogger.JsonFormatter):
    
        def parse(self):
            """
            他に出したいフィールドがあったらこのリストに足す
            https://docs.python.jp/3/library/logging.html
            """
            return [
                'process',
                'timestamp',
                'level',
                'temp(deg.)',
                'pressure(hPa)',
                'humid.(%)',    
            ]
    
        def add_fields(self, log_record, record, message_dict):
            super().add_fields(log_record, record, message_dict)
            if not log_record.get('timestamp'):
                # https://qiita.com/yoppe/items/4260cf4ddde69287a632
                now = datetime.datetime.now(timezone('Asia/Tokyo')).strftime('%Y-%m-%dT%H:%M:%S%z')
                log_record['timestamp'] = now
            if log_record.get('level'):
                log_record['level'] = log_record['level'].upper()
            else:
                log_record['level'] = record.levelname
    
    
    def getLogger(module_name):
        """プロジェクトごとにハンドラの設定などをしたい場合はここでやる"""
        logger = logging.getLogger(module_name)
        #handler = logging.FileHandler(filename, mode="w")
        handler = logging.handlers.TimedRotatingFileHandler(filename, encoding='utf-8',
            when='S', 
            interval=10, 
            backupCount=5,)
        handler.suffix = "%Y-%m-%d_%H%M%S.json"
        formatter = JsonFormatter()
        handler.setFormatter(formatter)
        logger.addHandler(handler)
        logger.setLevel(logging.DEBUG)
        return logger
    

    테스트를 위해 10초마다 회전하도록 하고 있습니다만, 실제의 운용시에는 when에 월요일 시작의 W0를 설정하려고 합니다.

    자세한 내용은 공식 문서에서 확인하십시오.

    가동 풍경



    1초마다 센서 데이터를 취득하여 10초마다 로그 로테이션하는 설정에서의 동작입니다.



    json 파일의 pandas에서 읽기



    readjson.py
    import json
    import pandas as pd
    
    filename = '20210202_thpLog.json'
    df = pd.read_json(filename, lines=True)
    print(df)
    

    에서 읽을 수 있습니다. 그리고는, 자유롭게.
    PS E:\Dropbox\00_works\Python\20210202_\json> python .\readJson.py
          process                     timestamp level  temp(deg.)  pressure(hPa)  humid.(%)
    0       19035 2021-02-02 10:40:22.837137920  INFO   23.369868    1000.237530  33.152283
    1       19035 2021-02-02 10:40:23.839900416  INFO   23.364816    1000.228997  33.072454
    2       19035 2021-02-02 10:40:24.842537984  INFO   23.364816    1000.282805  32.972641
    3       19035 2021-02-02 10:40:25.845187328  INFO   23.369868    1000.237530  32.912729
    4       19035 2021-02-02 10:40:26.847422208  INFO   23.369868    1000.237530  32.822892
    ...       ...                           ...   ...         ...            ...        ...
    2653    19035 2021-02-02 11:24:43.185660416  INFO   23.051628    1000.587428  29.506088
    2654    19035 2021-02-02 11:24:44.188551680  INFO   23.051628    1000.533646  29.531049
    2655    19035 2021-02-02 11:24:45.191405824  INFO   23.051628    1000.479865  29.645868
    2656    19035 2021-02-02 11:24:46.194267136  INFO   23.056680    1000.542184  29.950316
    2657    19035 2021-02-02 11:24:47.197230080  INFO   23.056680    1000.569075  29.815537
    
    [2658 rows x 6 columns]
    

    보충(시간대 변환)



    위의 스크립트는 기본적으로 timestamp 값을 날짜로 변환합니다.
    (자세한 내용은 여기을 확인하십시오.)

    이것은 좋지 않으므로 시간대를 변환합니다.

    제 경우에는 pyqtgraph를 사용하므로 unixtime으로 OK이지만 JST로 변환하는 경우도 설명합니다.
    import pandas as pd
    
    filename = '20210202_thpLog.json'
    
    # timezoneをJSTに変換する場合
    df_jst = pd.read_json(filename, lines=True).set_index('timestamp').tz_localize('UTC').tz_convert('Asia/Tokyo')
    print(df_jst)
    
    # unixtimeのまま使用する場合
    df_unixtime = pd.read_json(filename, lines=True, convert_dates=False)
    print(df_unixtime)
    

    위를 실행하면 다음과 같습니다.
    시간대 변환은 index만 대상이 되는 것 같습니다. . .
    timestamp를 index 열로 만든 다음 시간대 변환을 수행합니다.
    PS E:\Dropbox\00_works\Python\20210202_\json> python .\readJson.py
                                         process level  temp(deg.)  pressure(hPa)  humid.(%)
    timestamp
    2021-02-02 19:40:22.837137920+09:00    19035  INFO   23.369868    1000.237530  33.152283
    2021-02-02 19:40:23.839900416+09:00    19035  INFO   23.364816    1000.228997  33.072454
    2021-02-02 19:40:24.842537984+09:00    19035  INFO   23.364816    1000.282805  32.972641
    2021-02-02 19:40:25.845187328+09:00    19035  INFO   23.369868    1000.237530  32.912729
    2021-02-02 19:40:26.847422208+09:00    19035  INFO   23.369868    1000.237530  32.822892
    ...                                      ...   ...         ...            ...        ...
    2021-02-02 20:24:43.185660416+09:00    19035  INFO   23.051628    1000.587428  29.506088
    2021-02-02 20:24:44.188551680+09:00    19035  INFO   23.051628    1000.533646  29.531049
    2021-02-02 20:24:45.191405824+09:00    19035  INFO   23.051628    1000.479865  29.645868
    2021-02-02 20:24:46.194267136+09:00    19035  INFO   23.056680    1000.542184  29.950316
    2021-02-02 20:24:47.197230080+09:00    19035  INFO   23.056680    1000.569075  29.815537
    
    [2658 rows x 5 columns]
          process     timestamp level  temp(deg.)  pressure(hPa)  humid.(%)
    0       19035  1.612262e+09  INFO   23.369868    1000.237530  33.152283
    1       19035  1.612262e+09  INFO   23.364816    1000.228997  33.072454
    2       19035  1.612262e+09  INFO   23.364816    1000.282805  32.972641
    3       19035  1.612262e+09  INFO   23.369868    1000.237530  32.912729
    4       19035  1.612262e+09  INFO   23.369868    1000.237530  32.822892
    ...       ...           ...   ...         ...            ...        ...
    2653    19035  1.612265e+09  INFO   23.051628    1000.587428  29.506088
    2654    19035  1.612265e+09  INFO   23.051628    1000.533646  29.531049
    2655    19035  1.612265e+09  INFO   23.051628    1000.479865  29.645868
    2656    19035  1.612265e+09  INFO   23.056680    1000.542184  29.950316
    2657    19035  1.612265e+09  INFO   23.056680    1000.569075  29.815537
    
    [2658 rows x 6 columns]
    

    참고로 한 사이트



    로그 출력을 위한 print 와 import logging 을 그만두길 바래 - Qiita
    파이썬에서 json 형식으로 로그 내보내기 - Qiita

    좋은 웹페이지 즐겨찾기