Exemple #1
0
class SelfUpdate(WeatherModule):
    """
    Self update module

    This module detects git updates and updates itself.

    example config:
    {
      "module": "SelfUpdate",
      "config": {
        "check_interval": 86400
      }
    }
    """
    def __init__(self, fonts, location, language, units, config):
        self.check_interval = None
        if isinstance(config["check_interval"], int):
            self.check_interval = config["check_interval"]
        if self.check_interval is None:
            raise ValueError(__class__.__name__)

        self.timer_thread = RepeatedTimer(self.check_interval, self_update)
        self.timer_thread.start()

    def quit(self):
        if self.timer_thread:
            self.timer_thread.quit()
Exemple #2
0
    def __init__(self, fonts, location, language, units, config):
        self.check_interval = None
        if isinstance(config["check_interval"], int):
            self.check_interval = config["check_interval"]
        if self.check_interval is None:
            raise ValueError(__class__.__name__)

        self.timer_thread = RepeatedTimer(self.check_interval, self_update)
        self.timer_thread.start()
    def __init__(self, fonts, location, language, units, config):
        super().__init__(fonts, location, language, units, config)
        if "prefectures" in config and "city" in config:
            self.prefectures = config["prefectures"]
            self.city = config["city"]
        elif self.location["address"]:
            self.city, self.prefectures = self.location["address"].split(",")
        if not self.prefectures or not self.city:
            raise ValueError(__class__.__name__)

        # start weather alerts thread
        self.timer_thread = RepeatedTimer(600, weather_alerts,
                                          [self.prefectures, self.city])
        self.timer_thread.start()
def main():
    """main program
    """

    # initialize logger
    parser = argparse.ArgumentParser(description=__file__)
    parser.add_argument("--debug",
                        "-d",
                        action="store_const",
                        const=True,
                        default=False)
    parser.add_argument("--screenshot", "-s")
    args = parser.parse_args()
    logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO,
                        stream=sys.stdout,
                        format="%(asctime)s %(levelname)s %(message)s")

    # initialize thread
    timer_thread = None

    # initialize modules
    modules = []

    # initialize restart flag
    restart = False

    # initialize reboot flag
    reboot = False

    try:
        # load config file
        file = "/boot/WeatherPi.json"
        if not os.path.exists(file):
            file = "{}/config.json".format(sys.path[0])
        with open(file, "r") as f:
            config = json.loads(f.read())
        logging.info("%s loaded", file)

        # initialize locale, gettext
        language = config["locale"].split("_")[0]
        locale.setlocale(locale.LC_ALL, config["locale"])
        trans = gettext.translation("messages",
                                    localedir="{}/locale".format(sys.path[0]),
                                    languages=[language],
                                    fallback=True)
        trans.install()

        # initialize address, latitude and longitude
        if "google_api_key" in config and config["google_api_key"]:
            results = geocode(config["google_api_key"], language,
                              config["address"], config["latitude"],
                              config["longitude"])
            if results is not None:
                latitude, longitude, address = results
                config["latitude"] = latitude
                config["longitude"] = longitude
                config["address"] = address
                logging.info("location: %s,%s %s", latitude, longitude,
                             address)

        # start weather forecast thread
        timer_thread = RepeatedTimer(300, weather_forecast, [
            config["openweather_appid"], config["latitude"],
            config["longitude"], language, config["units"]
        ])
        timer_thread.start()

        # initialize pygame
        if "DISPLAY_NO" in config:
            os.putenv("DISPLAY", config["DISPLAY_NO"])
        if "SDL_FBDEV" in config:
            os.putenv("SDL_FBDEV", config["SDL_FBDEV"])
        pygame.init()
        pygame.mouse.set_visible(False)
        if pygame.display.mode_ok(config["display"]):
            display = screen = pygame.display.set_mode(config["display"])
            scale = None
        else:
            display = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
            screen = pygame.Surface(config["display"])
            display_w, display_h = display.get_size()
            screen_w, screen_h = screen.get_size()
            if display_w / screen_w * screen_h <= display_h:
                scale = (display_w, int(display_w / screen_w * screen_h))
            else:
                scale = (int(display_h / screen_h * screen_w), display_h)
        DISPLAY_SLEEP = pygame.USEREVENT + 1
        DISPLAY_WAKEUP = pygame.USEREVENT + 2
        RESTART = pygame.USEREVENT + 3
        REBOOT = pygame.USEREVENT + 4
        logging.info("pygame initialized. display:%s screen:%s scale:%s",
                     display.get_size(), screen.get_size(), scale)

        # load modules
        location = {
            "latitude": config["latitude"],
            "longitude": config["longitude"],
            "address": config["address"]
        }
        units = config["units"]
        fonts = config["fonts"]
        modules = []
        for module in config["modules"]:
            name = module["module"]
            conf = module["config"]
            if name in globals():
                logging.info("load built-in module: %s", name)
                mod = (globals()[name])
            else:
                logging.info("load external module: %s", name)
                mod = getattr(
                    importlib.import_module("modules.{}".format(name)), name)
            modules.append((mod)(fonts, location, language, units, conf))
        logging.info("modules loaded")

        # main loop
        display_wakeup = True
        last_hash_value = None
        running = True
        while running:
            # weather data check
            weather = timer_thread.get_result()
            updated = False
            if weather:
                hash_value = timer_thread.get_hash_value()
                if last_hash_value != hash_value:
                    logging.info("weather data updated")
                    last_hash_value = hash_value
                    updated = True

            # update screen
            for module in modules:
                module.draw(screen, weather, updated)

            # update display
            if display_wakeup:
                if scale:
                    # fit to display
                    display.blit(pygame.transform.scale(screen, scale), (0, 0))
                pygame.display.flip()

            # event check
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False
                elif event.type == RESTART:
                    running = False
                    restart = True
                elif event.type == REBOOT:
                    running = False
                    reboot = True
                elif event.type == DISPLAY_SLEEP:
                    if display_wakeup:
                        display.fill(pygame.Color("black"))
                        pygame.display.flip()
                        display_wakeup = False
                elif event.type == DISPLAY_WAKEUP:
                    if not display_wakeup:
                        last_hash_value = None
                        display_wakeup = True

            time.sleep(1)

    except Exception as e:
        logging.error(e, exc_info=True)

    finally:
        if args.screenshot:
            pygame.image.save(display, args.screenshot)
        if timer_thread:
            timer_thread.quit()
        for module in modules:
            module.quit()
        pygame.quit()
        if restart:
            logging.info("restarting..")
            os.execl(sys.executable, sys.executable, *sys.argv)
        if reboot:
            os.system('sudo reboot')
        sys.exit()
class JMAAlerts(WeatherModule):
    """
    気象庁 (Japan Meteorological Agency) alerts module

    example config:
    {
      "module": "JMAAlerts",
      "config": {
        "rect": [x, y, width, height],
        "prefectures": "東京都",
        "city": "中央区"
       }
    }

    気象庁防災情報XMLフォーマット形式電文の公開(PULL型)で公開されているAtomフィードのうち、
    "高頻度フィード/随時"のフィードに掲載された都道府県のデータフィードから、指定した市区町村の
    注意報、警報、特別警報を取得し、表示する。

    参考:http://xml.kishou.go.jp/xmlpull.html
    """
    def __init__(self, fonts, location, language, units, config):
        super().__init__(fonts, location, language, units, config)
        if "prefectures" in config and "city" in config:
            self.prefectures = config["prefectures"]
            self.city = config["city"]
        elif self.location["address"]:
            self.city, self.prefectures = self.location["address"].split(",")
        if not self.prefectures or not self.city:
            raise ValueError(__class__.__name__)

        # start weather alerts thread
        self.timer_thread = RepeatedTimer(600, weather_alerts,
                                          [self.prefectures, self.city])
        self.timer_thread.start()

    def quit(self):
        if self.timer_thread:
            self.timer_thread.quit()

    def draw(self, screen, weather, updated):
        if weather is None:
            message = "Waiting data..."
        else:
            result = self.timer_thread.get_result()
            if result:
                message = ",".join(list(map(_, result)))
            else:
                message = ""

        self.clear_surface()
        if message:
            logging.info("%s: %s", __class__.__name__, message)
            if "特別警報" in message:
                color = "violet"
            elif "警報" in message:
                color = "red"
            elif "注意報" in message:
                color = "yellow"
            else:
                color = "white"
            for size in ("large", "medium", "small"):
                w, h = self.text_size(message, size, bold=True)
                if w <= self.rect.width and h <= self.rect.height:
                    break
            self.draw_text(message, (0, 0),
                           size,
                           color,
                           bold=True,
                           align="center")
        self.update_screen(screen)
Exemple #6
0
 def start_sensor_thread(self, interval, function, args=None, kwargs=None):
     """start sensor thread
     """
     self.sensor_thread = RepeatedTimer(interval, function, args, kwargs)
     self.sensor_thread.start()
Exemple #7
0
class TemperatureModule(WeatherModule):
    """
    Temperature and humidity sensor module class
    """
    def __init__(self, fonts, location, language, units, config):
        super().__init__(fonts, location, language, units, config)
        self.sensor_thread = None
        self.last_hash_value = None

        # histrical data
        self.window_size = 6 * 60
        now = datetime.datetime.now()
        self.times = [
            now - datetime.timedelta(minutes=x)
            for x in range(0, self.window_size)
        ]
        self.times.reverse()
        self.temperatures = [np.nan] * self.window_size
        self.humidities = [np.nan] * self.window_size

        # logging setup
        self.logfile = None
        if "logfile" in config:
            self.logfile = config["logfile"]
            if not os.path.isfile(self.logfile):
                with open(self.logfile, mode="w") as f:
                    f.write("Date,Temperature,Humidity¥n")

        # glaph module setup
        self.graph_module = None
        if "graph_rect" in config:
            config["rect"] = config["graph_rect"]
            self.graph_module = TemperatureGraph(fonts, location, language,
                                                 units, config)

    def start_sensor_thread(self, interval, function, args=None, kwargs=None):
        """start sensor thread
        """
        self.sensor_thread = RepeatedTimer(interval, function, args, kwargs)
        self.sensor_thread.start()

    def get_sensor_value(self):
        """read last sensor value
        """
        # No result yet
        result = self.sensor_thread.get_result()
        if result is None:
            logging.info("%s: No data from sensor", __class__.__name__)
            self.last_hash_value = None
            return (None, None, False)

        (celsius, humidity) = result

        # logging only once a minute
        dt = datetime.datetime.now()
        if dt.second == 0:
            self.times = self.times[1:] + [dt]
            if self.temperatures is not None:
                celsius = np.nan if celsius is None else float(
                    celsius if self.units ==
                    "metric" else Utils.fahrenheit(celsius))
                self.temperatures = self.temperatures[1:] + [celsius]
            else:
                celsius = None
            if self.humidities is not None:
                humidity = np.nan if humidity is None else float(humidity)
                self.humidities = self.humidities[1:] + [humidity]
            else:
                humidity = None
            if self.logfile:
                with open(self.logfile, mode="a") as f:
                    f.write("{},{},{}\n".format(dt, celsius, humidity))

        # Has the value changed
        hash_value = self.sensor_thread.get_hash_value()
        if self.last_hash_value == hash_value:
            return (celsius, humidity, False)

        self.last_hash_value = hash_value
        return (celsius, humidity, True)

    def draw_graph(self, screen, _weather, _updated):
        """draw temperature and humidity graph
        """
        if self.graph_module:
            self.graph_module.draw_graph(screen, self.times, self.temperatures,
                                         self.humidities)

    def quit(self):
        if self.sensor_thread:
            self.sensor_thread.quit()