def scan(self) -> bool:
        """SKSCANでスマートメーターを探し、接続パラメータを取得.

        Returns:
            成功したときはパラメータをselfに設定し、Trueを返す。
        """
        params: typ.Dict[str, str] = self.sk.scan_pan()
        if len(params) == 0:
            print("スマートメーターが見つかりませんでした。")
            return False
        channel: str = params["Channel"]
        channel_page: str = params.get("Channel Page", "0")
        pan_id: str = params["Pan ID"]
        addr: str = params["Addr"]
        lqi: str = params.get("LQI", "0")
        pair_id: str = params.get("PairID", "")

        store: db_store.DBStore = db_store.DBStore(self.db_url)
        store.scan_log(int(channel, 16), int(channel_page, 16),
                       int(pan_id, 16), addr, int(lqi, 16), pair_id)
        del store

        ipv6addr: str = self.sk.skll64(addr)
        if not re.match(r"([0-9A-F]{4}:){7}[0-9A-F]{4}", ipv6addr):
            print(f"スマートメーターのIPv6アドレスの取得に失敗しました。 [{ipv6addr}]")
            return False
        # 接続パラメータをselfに保存する。
        self.channel = channel
        self.pan_id = pan_id
        self.ipv6addr = ipv6addr
        return True
    def get_prop(self) -> bool:
        """property値読み出し.

        Returns:
            成功したときTrue
        """
        epc_list: typ.List[int] = [
            echonet.EPC_係数,
            echonet.EPC_積算電力量計測値,
            echonet.EPC_積算電力量単位,
            echonet.EPC_瞬時電力計測値,
            echonet.EPC_瞬時電流計測値,
        ]
        props: typ.Optional[typ.List] = self.sk.get_prop(
            self.ipv6addr,
            epc_list,
        )
        if props is None:
            return False

        propdict: typ.Dict[int, bytes] = {}
        for p in props:
            propdict[p.epc] = p.edt

        係数: typ.Optional[int] = None
        積算電力量: typ.Optional[int] = None
        電力量単位: typ.Optional[int] = None
        瞬時電力: typ.Optional[int] = None
        瞬時電流_R: typ.Optional[int] = None
        瞬時電流_T: typ.Optional[int] = None
        if echonet.EPC_係数 in propdict:
            係数 = struct.unpack_from("!L", propdict[echonet.EPC_係数])[0]
        if echonet.EPC_積算電力量計測値 in propdict:
            積算電力量 = struct.unpack_from("!L", propdict[echonet.EPC_積算電力量計測値])[0]
        if echonet.EPC_積算電力量単位 in propdict:
            電力量単位 = struct.unpack_from("B", propdict[echonet.EPC_積算電力量単位])[0]
        if echonet.EPC_瞬時電力計測値 in propdict:
            瞬時電力 = struct.unpack_from("!l", propdict[echonet.EPC_瞬時電力計測値])[0]
        if echonet.EPC_瞬時電流計測値 in propdict:
            瞬時電流_R = struct.unpack_from("!h", propdict[echonet.EPC_瞬時電流計測値])[0]
            瞬時電流_T = struct.unpack_from("!h", propdict[echonet.EPC_瞬時電流計測値],
                                        2)[0]

        store: db_store.DBStore = db_store.DBStore(self.db_url)
        store.power_log(係数, 積算電力量, 電力量単位, 瞬時電力, 瞬時電流_R, 瞬時電流_T)
        del store

        self.add_zabbix("coefficient", 係数)
        self.add_zabbix("energy", 積算電力量)
        self.add_zabbix("energy_unit", 電力量単位)
        self.add_zabbix("power", 瞬時電力)
        self.add_zabbix("current_R", 瞬時電流_R)
        self.add_zabbix("current_T", 瞬時電流_T)

        return True
    def log_bme280(self) -> typ.Tuple:
        """BME280の情報を記録する.

        Returns:
            気圧, 気温, 湿度
        """
        d: typ.Tuple = self.bme280.read()
        store: db_store.DBStore = db_store.DBStore(self.db_url)
        store.bme280_log(d[1], d[0], d[2])
        del store
        self.add_zabbix("temperature", d[1])
        self.add_zabbix("pressure", d[0])
        self.add_zabbix("humidity", d[2])
        return d
    def log_temp(self) -> float:
        """温度を記録する.

        Returns:
            CPU温度
        """
        with open("/sys/class/thermal/thermal_zone0/temp", "r") as f:
            temp: int = int(f.readline())

        store: db_store.DBStore = db_store.DBStore(self.db_url)
        store.temp_log(temp)
        del store
        self.add_zabbix("cpu_temperature", temp)
        return float(temp)
    def log_co2(self) -> typ.Tuple[int, float]:
        """CO2を記録する.

        Returns:
            CO2濃度, 気温
        """
        d: typ.Dict = mh_z19.read_all(serial_console_untouched=True)
        self.sk.debug_print(f"MH_Z19: {d}")
        if "co2" in d:
            store: db_store.DBStore = db_store.DBStore(self.db_url)
            store.co2_log(d["co2"], d["temperature"], d["UhUl"], d["SS"])
            del store
            self.add_zabbix("co2", d["co2"])
            return (d["co2"], d["temperature"])
        return (0, 0)
예제 #6
0
def main() -> None:
    """メイン処理."""
    parser: argparse.ArgumentParser = argparse.ArgumentParser()
    parser.add_argument("-o", "--output", help="output filename")
    parser.add_argument("-s", "--start", help="start time")
    parser.add_argument("-e", "--end", help="end time")
    parser.add_argument("-d", "--days", type=int, help="before n days")
    parser.add_argument("-w",
                        "--window",
                        type=int,
                        help="window size of moving average",
                        default=30)

    args: argparse.Namespace = parser.parse_args()

    today: datetime.date = datetime.date.today()

    start_time: datetime.datetime = datetime.datetime.combine(
        today, datetime.time())
    if args.start:
        start_time = datetime.datetime.fromisoformat(args.start)
    end_time: datetime.datetime = start_time + datetime.timedelta(days=1)
    if args.end:
        end_time = datetime.datetime.fromisoformat(args.end)
    if args.days:
        end_time = datetime.datetime.now()
        start_time = end_time - datetime.timedelta(args.days)
    output_file: str = f"power_{start_time.date()}.html"
    if args.output:
        if os.path.isdir(args.output):
            output_file = os.path.join(args.output, output_file)
        else:
            output_file = args.output

    inifile: configparser.ConfigParser = configparser.ConfigParser()
    inifile.read("power_consumption.ini", "utf-8")
    db_url: str = inifile.get("routeB", "db_url")

    store: db_store.DBStore = db_store.DBStore(db_url)
    data: typ.List = store.select_power_log(start_time, end_time)

    make_power_graph(output_file, data, args.window)
    print(output_file)
예제 #7
0
def main() -> None:
    """メイン処理."""
    parser: argparse.ArgumentParser = argparse.ArgumentParser()
    parser.add_argument("-o", "--output", help="output filename")
    parser.add_argument("-s", "--start", help="start time")
    parser.add_argument("-e", "--end", help="end time")
    parser.add_argument("-d", "--days", type=int, help="before n days")

    args: argparse.Namespace = parser.parse_args()

    today: datetime.date = datetime.date.today()

    start_time: datetime.datetime = datetime.datetime.combine(
        today, datetime.time())
    if args.start:
        start_time = datetime.datetime.fromisoformat(args.start)
    end_time: datetime.datetime = start_time + datetime.timedelta(days=1)
    if args.end:
        end_time = datetime.datetime.fromisoformat(args.end)
    if args.days:
        end_time = datetime.datetime.now()
        start_time = end_time - datetime.timedelta(args.days)
    output_file: str = f"temp_{start_time.date()}.html"
    if args.output:
        if os.path.isdir(args.output):
            output_file = os.path.join(args.output, output_file)
        else:
            output_file = args.output

    inifile: configparser.ConfigParser = configparser.ConfigParser()
    inifile.read("power_consumption.ini", "utf-8")
    db_url: str = inifile.get("routeB", "db_url")

    store: db_store.DBStore = db_store.DBStore(db_url)
    temp_data: typ.List = store.select_temp_log(start_time, end_time)
    co2_data: typ.List = store.select_co2_log(start_time, end_time)
    bme280_data: typ.List = store.select_bme280_log(start_time, end_time)

    if len(temp_data) > 0 or len(co2_data) > 0 or len(bme280_data) > 0:
        make_temp_graph(output_file, temp_data, co2_data, bme280_data)
        print(output_file)
    else:
        print("no data")
예제 #8
0
def main() -> None:
    """メイン処理."""
    parser: argparse.ArgumentParser = argparse.ArgumentParser()
    parser.add_argument("-o", "--output", help="output filename")

    args: argparse.Namespace = parser.parse_args()

    output_file: str = f"latest.html"
    if args.output:
        if os.path.isdir(args.output):
            output_file = os.path.join(args.output, output_file)
        else:
            output_file = args.output

    inifile: configparser.ConfigParser = configparser.ConfigParser()
    inifile.read("power_consumption.ini", "utf-8")
    db_url: str = inifile.get("routeB", "db_url")

    store: db_store.DBStore = db_store.DBStore(db_url)
    data: typ.Dict = store.select_latest_log()

    with open(output_file, "w", newline="\r\n") as out:
        out.writelines([
            "<!DOCTYPE html>\n",
            "<html lang='ja'>\n",
            "<head>\n",
            "<meta charset='utf-8'/>\n",
            "<meta name='viewport' content='width=device-width, initial-scale=1.0, user-scalable=yes'>\n",
            "<style type='text/css'>\n",
            "body { font-size: x-large; }\n",
            ".red { color: red; }\n",
            ".blue { color: blue; }\n",
            ".green { color: green; }\n",
            ".right { text-align: right; }\n",
            "</style>\n",
            "</head>\n",
            "<body>\n",
            "<table>\n"
        ])
        if data["power"] is not None:
            created_at: str = data["power"]["created_at"].strftime("%Y/%m/%d %H:%M:%S")
            瞬時電力: int = data["power"]["瞬時電力"]
            瞬時電流: float = (data["power"]["瞬時電流_r"] + data["power"]["瞬時電流_t"]) / 10
            電流_color: str = ""
            if 瞬時電流 > 28:
                電流_color = "red"
            elif 瞬時電流 > 15:
                電流_color = "blue"
            out.write(f"<tr><td colspan=3>{created_at}</td></tr>\n")
            out.write(f"<tr><td>瞬時電力</td><td class='right'>{瞬時電力}</td><td>[W]</td></tr>\n")
            out.write(f"<tr><td>瞬時電流</td><td class='right {電流_color}'>{瞬時電流}</td><td>[A]</td></tr>\n")
        if data["temp"] is not None:
            CPU: float = data["temp"]["temp"] / 1000
            out.write(f"<tr><td>CPU温度</td><td class='right'>{CPU:.1f}</td><td>[℃]</td></tr>\n")
        if data["co2"] is not None:
            CO2: int = data["co2"]["co2"]
            co2_color: str = "blue"
            if CO2 > 2000:
                co2_color = "red"
            elif CO2 > 1000:
                co2_color = "green"
            #temp: int = data["co2"]["temp"]
            out.write(f"<tr><td>CO₂濃度</td><td class='right {co2_color}'>{CO2}</td><td>[ppm]</td></tr>\n")
            #out.write(f"<tr><td>気温</td><td class='right'>{temp}</td><td>[℃]</td></tr>\n")
        if data["bme280"] is not None:
            temp: float = data["bme280"]["temp"]
            hum: float = data["bme280"]["humidity"]
            pres: float = data["bme280"]["pressure"]
            temp_color: str = "green"
            if temp < 18:
                temp_color = "blue"
            elif temp > 25:
                temp_color = "red"
            hum_color: str = "green"
            if hum < 40:
                hum_color = "blue"
            elif hum > 65:
                hum_color = "red"
            out.write(f"<tr><td>気温</td><td class='right {temp_color}'>{temp:.1f}</td><td>[℃]</td></tr>\n")
            out.write(f"<tr><td>湿度</td><td class='right {hum_color}'>{hum:.1f}</td><td>[%]</td></tr>\n")
            out.write(f"<tr><td>気圧</td><td class='right'>{pres:.1f}</td><td>[hPa]</td></tr>\n")
        out.writelines([
            "</table>\n"
            "</body>\n",
            "</html>\n",
        ])