Ejemplo n.º 1
0
def tv_channel():
    redis = get_redis()
    channel = redis.get("tvchannel").decode("utf-8")
    id_ = redis.get("tvid").decode("utf-8") or 0
    if channel is None:
        channel = restore_default_tv_channel()
    return jsonify(channel=channel, id=id_)
Ejemplo n.º 2
0
 def run(self, context: CommandContext):
     if len(context.args) != 1:
         context.api.chat_post_ephemeral({
             'channel': context.event.channel,
             'user': context.event.user,
             'text': f'Expected a single argument (f/c)'
         })
         return
     units, = context.args
     units = units.lower()
     unit_map = {
         'fahrenheit': 'us',
         'f': 'us',
         'celsius': 'si',
         'c': 'si'
     }
     if units not in unit_map:
         context.api.chat_post_ephemeral(
             {
                 'channel': context.event.channel,
                 'user': context.event.user,
                 'text': f'Units must either be `f` or `c`. Got {units}'
             }
         )
         return
     redis = get_redis()
     redis.hset('user_units', context.event.user, unit_map[units])
     context.api.chat_post_ephemeral(
         {
             'channel': context.event.channel,
             'user': context.event.user,
             'text': f'Set default units to {units}'
         }
     )
Ejemplo n.º 3
0
 def run(self, context: CommandContext):
     if len(context.args) != 1:
         context.api.chat_post_ephemeral(
             {
                 "channel": context.event.channel,
                 "user": context.event.user,
                 "text": "Expected a single argument (f/c)",
             }
         )
         return
     (units,) = context.args
     units = units.lower()
     unit_map = {"fahrenheit": "us", "f": "us", "celsius": "si", "c": "si"}
     if units not in unit_map:
         context.api.chat_post_ephemeral(
             {
                 "channel": context.event.channel,
                 "user": context.event.user,
                 "text": f"Units must either be `f` or `c`. Got {units}",
             }
         )
         return
     redis = get_redis()
     redis.hset("user_units", context.event.user, unit_map[units])
     context.api.chat_post_ephemeral(
         {
             "channel": context.event.channel,
             "user": context.event.user,
             "text": f"Set default units to {units}",
         }
     )
Ejemplo n.º 4
0
    def get_message_args(self, context: CommandContext):
        team_id = context.team_id
        user_id = context.event.user
        ts = time.time()
        redis = get_redis()
        last_poke_time_key = f'poke:last:{team_id}'
        user_count_key = f'poke:user:{team_id}'
        last_poke_user_key = f'poke:lastuser:{team_id}'
        last_poke_time = redis.get(last_poke_time_key)
        redis.set(last_poke_time_key, ts)
        last_poked_user_id = redis.get(last_poke_user_key)
        if last_poked_user_id:
            last_poked_user_id = last_poked_user_id.decode('utf-8')
        redis.set(last_poke_user_key, user_id)
        total_pokes = redis.hincrby(user_count_key, user_id)

        if last_poke_time is None:
            return {
                'icon_emoji':
                f'{Emoji.SHOOKCAT}',
                'text': (f'You have poked meowbot 1 time!\n\n'
                         'You\'re the first to poke meowbot!')
            }

        s = '' if total_pokes == 1 else 's'
        last_poke = arrow.get(float(last_poke_time)).humanize()
        last_user = quote_user_id(last_poked_user_id)
        return {
            'icon_emoji':
            f'{Emoji.SHOOKCAT}',
            'text':
            f'You have poked meowbot {total_pokes} time{s}!\n\n'
            f'Meowbot was last poked {last_poke} by {last_user}'
        }
Ejemplo n.º 5
0
    def get_message_args(self, context: CommandContext):
        team_id = context.team_id
        user_id = context.event.user
        ts = time.time()
        redis = get_redis()
        last_poke_time_key = f"poke:last:{team_id}"
        user_count_key = f"poke:user:{team_id}"
        last_poke_user_key = f"poke:lastuser:{team_id}"
        last_poke_time = redis.get(last_poke_time_key)
        redis.set(last_poke_time_key, ts)
        last_poked_user_id = redis.get(last_poke_user_key)
        if last_poked_user_id:
            last_poked_user_id = last_poked_user_id.decode("utf-8")
        redis.set(last_poke_user_key, user_id)
        total_pokes = redis.hincrby(user_count_key, user_id)

        if last_poke_time is None:
            return {
                "icon_emoji":
                f"{Emoji.SHOOKCAT}",
                "text": ("You have poked meowbot 1 time!\n\n"
                         "You're the first to poke meowbot!"),
            }

        s = "" if total_pokes == 1 else "s"
        last_poke = arrow.get(float(last_poke_time)).humanize()
        last_user = quote_user_id(last_poked_user_id)
        return {
            "icon_emoji":
            f"{Emoji.SHOOKCAT}",
            "text":
            f"You have poked meowbot {total_pokes} time{s}!\n\n"
            f"Meowbot was last poked {last_poke} by {last_user}",
        }
Ejemplo n.º 6
0
 def get_message_args(self, context: CommandContext):
     redis = get_redis()
     redis.set('killtv', '1')
     restore_default_tv_channel()
     return {
         'text': ('Meowbot TV has been disabled. '
                  'Contact Meowbot admin to reenable')
     }
Ejemplo n.º 7
0
 def run(self, context: CommandContext):
     location = ' '.join(context.args)
     redis = get_redis()
     redis.hset('user_location', context.event.user, location)
     context.api.chat_post_ephemeral({
         'channel': context.event.channel,
         'user': context.event.user,
         'text': f'Set default location to {location}'
     })
Ejemplo n.º 8
0
Archivo: tv.py Proyecto: pbhuss/meowbot
    def get_message_args(self, context: CommandContext):
        redis = get_redis()
        if redis.exists("killtv"):
            admin_user_id = get_admin_user_id()
            return {
                "text": (
                    "Meowbot TV has been disabled. "
                    f"Contact {quote_user_id(admin_user_id)} to reenable"
                )
            }

        channels = get_channels()
        available_channels = ", ".join(sorted(channels.keys()))
        if len(context.args) == 1:
            (channel,) = context.args
            if channel not in channels:
                return {
                    "text": f"{channel} is not a valid channel.\n\n"
                    f"Available channels: {available_channels}",
                    "thread_ts": context.event.ts,
                }
            redis.incr("tvid")
            redis.set("tvchannel", channels[channel]["url"])
            return {
                "text": f'Changing channel to {channels[channel]["name"]}!',
            }
        elif len(context.args) == 2:
            channel_type, value = context.args
            if channel_type == "url":
                url = value[1:-1]
                redis.incr("tvid")
                redis.set("tvchannel", url)
                return {
                    "text": f"Changing channel to {url}!",
                }
            elif channel_type == "twitch":
                url = f"https://player.twitch.tv/?channel={value}"
                redis.incr("tvid")
                redis.set("tvchannel", url)
                return {
                    "text": f"Changing channel to {Emoji.TWITCH} {value}!",
                }
            elif channel_type == "youtube":
                url = (
                    f"https://www.youtube.com/embed/{value}?"
                    f"autoplay=1&loop=1&playlist={value}"
                )
                redis.incr("tvid")
                redis.set("tvchannel", url)
                return {
                    "text": f"Changing channel to {Emoji.YOUTUBE} {value}!",
                }
        return {
            "text": "Must provide a channel.\n\n"
            f"Available channels: {available_channels}",
            "thread_ts": context.event.ts,
        }
Ejemplo n.º 9
0
 def get_message_args(self, context: CommandContext):
     if len(context.args) == 0:
         return {"text": "must specify at least one argument"}
     redis = get_redis()
     func_name, *func_args = context.args
     func = getattr(redis, func_name, None)
     if func is None:
         return {"text": f"invalid func_name: {func_name}"}
     arg_names = ", ".join(func_args)
     ret = func(*func_args)
     return {"text": f"Ran `{func_name}({arg_names})`\nReturned `{ret}`"}
Ejemplo n.º 10
0
 def run(self, context: CommandContext):
     location = " ".join(context.args)
     redis = get_redis()
     redis.hset("user_location", context.event.user, location)
     context.api.chat_post_ephemeral(
         {
             "channel": context.event.channel,
             "user": context.event.user,
             "text": f"Set default location to {location}",
         }
     )
Ejemplo n.º 11
0
Archivo: tv.py Proyecto: pbhuss/meowbot
 def get_message_args(self, context: CommandContext):
     redis = get_redis()
     redis.set("killtv", "1")
     restore_default_tv_channel()
     admin_user_id = get_admin_user_id()
     return {
         "text": (
             "Meowbot TV has been disabled. "
             f"Contact {quote_user_id(admin_user_id)} to reenable"
         )
     }
Ejemplo n.º 12
0
 def get_message_args(self, context: CommandContext):
     redis = get_redis()
     if len(context.args) >= 1:
         query = " ".join(context.args)
     else:
         if redis.hexists(USER_LOCATION, context.event.user):
             query = redis.hget(USER_LOCATION, context.event.user).decode("utf-8")
         else:
             query = get_default_zip_code()
     if redis.hexists(USER_UNITS, context.event.user):
         units = redis.hget(USER_UNITS, context.event.user).decode("utf-8")
     else:
         units = DEFAULT_UNITS
     return self._weather_arguments(query, units=units)
Ejemplo n.º 13
0
    def get_message_args(self, context: CommandContext):
        redis = get_redis()
        if redis.exists('killtv'):
            return {
                'text': ('Meowbot TV has been disabled. '
                         'Contact Meowbot admin to reenable')
            }

        channels = get_channels()
        available_channels = ', '.join(sorted(channels.keys()))
        if len(context.args) == 1:
            channel, = context.args
            if channel not in channels:
                return {
                    'text': f'{channel} is not a valid channel.\n\n'
                    f'Available channels: {available_channels}',
                    'thread_ts': context.event.ts
                }
            redis.set('tvchannel', channels[channel]['url'])
            return {
                'text': f'Changing channel to {channels[channel]["name"]}!',
            }
        elif len(context.args) == 2:
            channel_type, value = context.args
            if channel_type == 'url':
                url = value[1:-1]
                redis.set('tvchannel', url)
                return {
                    'text': f'Changing channel to {url}!',
                }
            elif channel_type == 'twitch':
                url = f'https://player.twitch.tv/?channel={value}'
                redis.set('tvchannel', url)
                return {
                    'text': f'Changing channel to {Emoji.TWITCH} {value}!',
                }
            elif channel_type == 'youtube':
                url = (f'https://www.youtube.com/embed/{value}?'
                       f'autoplay=1&loop=1&playlist={value}')
                redis.set('tvchannel', url)
                return {
                    'text': f'Changing channel to {Emoji.YOUTUBE} {value}!',
                }
        return {
            'text': 'Must provide a channel.\n\n'
            f'Available channels: {available_channels}',
            'thread_ts': context['event']['ts']
        }
Ejemplo n.º 14
0
    def get_message_args(self, context: CommandContext):
        redis = get_redis()
        key = "concertcal"
        ical_data = redis.get(key)
        if ical_data is None:
            ical_data = requests.get(
                "https://ybgfestival.org/events/?ical=1&tribe_display=list"
            ).content
            redis.set(key, ical_data)
            # Expire at midnight PST
            redis.expireat(
                key,
                (arrow.utcnow().to("US/Pacific") + timedelta(days=1)).replace(
                    hour=0, minute=0).timestamp,
            )

        cal = ics.Calendar(ical_data.decode("utf-8"))
        events = cal.timeline.start_after(arrow.utcnow() - timedelta(hours=3))
        colors = ["#7aff33", "#33a2ff"]
        return {
            "text":
            "Upcoming concerts at <https://ybgfestival.org/|"
            "Yerba Buena Gardens Festival>:",
            "attachments": [{
                "title":
                event.name,
                "title_link":
                event.url,
                "text":
                event.description,
                "color":
                color,
                "fields": [
                    {
                        "title":
                        "When",
                        "value":
                        "{} - {}".format(
                            event.begin.strftime("%a %b %d, %I:%M"),
                            event.end.strftime("%I:%M %p"),
                        ),
                        "short":
                        False,
                    },
                ],
            } for event, color in zip(events, colors)],
        }
Ejemplo n.º 15
0
    def get_message_args(self, context: CommandContext):
        redis = get_redis()
        key = 'concertcal'
        ical_data = redis.get(key)
        if ical_data is None:
            ical_data = requests.get(
                'https://ybgfestival.org/events/?ical=1&tribe_display=list'
            ).content
            redis.set(key, ical_data)
            # Expire at midnight PST
            redis.expireat(
                key,
                (arrow.utcnow().to('US/Pacific') + timedelta(days=1)).replace(
                    hour=0, minute=0).timestamp
            )

        cal = ics.Calendar(ical_data.decode('utf-8'))
        events = cal.timeline.start_after(arrow.utcnow() - timedelta(hours=3))
        colors = ['#7aff33', '#33a2ff']
        return {
            'text': 'Upcoming concerts at <https://ybgfestival.org/|'
                    'Yerba Buena Gardens Festival>:',
            'attachments': [
                {
                    'title': event.name,
                    'title_link': event.url,
                    'text': event.description,
                    'color': color,
                    'fields': [
                        {
                            'title': 'When',
                            'value': '{} - {}'.format(
                                event.begin.strftime('%a %b %d, %I:%M'),
                                event.end.strftime('%I:%M %p')
                            ),
                            'short': False
                        },
                    ]
                }
                for event, color in zip(events, colors)
            ]
        }
Ejemplo n.º 16
0
Archivo: tv.py Proyecto: pbhuss/meowbot
 def get_message_args(self, context: CommandContext):
     redis = get_redis()
     redis.delete("killtv")
     return {
         "text": "Meowbot TV has been enabled",
     }
Ejemplo n.º 17
0
def tv_channel():
    redis = get_redis()
    channel = redis.get('tvchannel')
    if channel is None:
        channel = restore_default_tv_channel()
    return channel
Ejemplo n.º 18
0
    def _weather_arguments(self, query, units):
        key = f"weather:{units}:{query}"
        redis = get_redis()
        data = redis.get(key)
        location = get_location(query)
        if location is None:
            return {"text": f"Location `{query}` not found"}

        icon_map = {
            "clear-day": Emoji.SUNNY,
            "clear-night": Emoji.CRESCENT_MOON,
            "rain": Emoji.RAIN_CLOUD,
            "snow": Emoji.SNOW_CLOUD,
            "sleet": Emoji.RAIN_CLOUD,
            "wind": Emoji.WIND_BLOWING_FACE,
            "fog": Emoji.FOG,
            "cloudy": Emoji.CLOUD,
            "partly-cloudy-day": Emoji.PARTLY_SUNNY,
            "partly-cloudy-night": Emoji.PARTLY_SUNNY,
        }
        icon_default = Emoji.EARTH_AFRICA

        if data is None:
            api_key = get_darksky_api_key()
            lat = location["lat"]
            lon = location["lon"]
            data = requests.get(
                f"https://api.darksky.net/forecast/{api_key}/{lat},{lon}",
                params={
                    "exclude": "minutely,alerts,flags",
                    "lang": "en",
                    "units": units,
                },
            ).content
            redis.set(key, data, ex=5 * 60)

        result = json.loads(data.decode("utf-8"))

        temp_symbol = "℉" if units == "us" else "℃"
        other_symbol = "℃" if units == "us" else "℉"
        other_unit = "si" if units == "us" else "us"

        return {
            "blocks": [
                {
                    "type": "section",
                    "text": {
                        "type": "mrkdwn",
                        "text": f'*Forecast for {location["display_name"]}*',
                    },
                },
                {
                    "type": "actions",
                    "elements": [
                        {
                            "type": "button",
                            "action_id": f"weather:{units}",
                            "text": {
                                "type": "plain_text",
                                "text": (f"{Emoji.ARROWS_COUNTERCLOCKWISE} Refresh"),
                                "emoji": True,
                            },
                            "value": str(query),
                        },
                        {
                            "type": "button",
                            "action_id": f"weather:{other_unit}",
                            "text": {
                                "type": "plain_text",
                                "text": f"to {other_symbol}",
                            },
                            "value": str(query),
                        },
                    ],
                },
                {"type": "divider"},
                {
                    "type": "section",
                    "text": {
                        "type": "mrkdwn",
                        "text": "*Current Weather*\n{summary}\n"
                        "{icon} {current_temperature}{temp_unit}\n".format(
                            summary=result["hourly"]["summary"],
                            icon=icon_map.get(
                                result["currently"]["icon"], icon_default
                            ),
                            current_temperature=int(result["currently"]["temperature"]),
                            temp_unit=temp_symbol,
                        ),
                    },
                },
                {"type": "divider"},
                {
                    "type": "section",
                    "text": {"type": "mrkdwn", "text": "*This Week*"},
                    "fields": [
                        {
                            "type": "mrkdwn",
                            "text": (
                                "*{day}*\n{icon} {high}{temp_unit} / "
                                "{low}{temp_unit}".format(
                                    day=arrow.get(day["time"]).format("ddd"),
                                    icon=icon_map.get(day["icon"], icon_default),
                                    high=int(day["temperatureHigh"]),
                                    low=int(day["temperatureLow"]),
                                    temp_unit=temp_symbol,
                                )
                            ),
                        }
                        for day in result["daily"]["data"]
                    ],
                },
                {
                    "type": "context",
                    "elements": [
                        {
                            "type": "mrkdwn",
                            "text": "<https://darksky.net/poweredby/|"
                            "Powered by Dark Sky>",
                        }
                    ],
                },
            ]
        }
Ejemplo n.º 19
0
    def _weather_arguments(self, query, units):
        key = f'weather:{units}:{query}'
        redis = get_redis()
        data = redis.get(key)
        location = get_location(query)
        if location is None:
            return {'text': f'Location `{query}` not found'}

        icon_map = {
            'clear-day': Emoji.SUNNY,
            'clear-night': Emoji.CRESCENT_MOON,
            'rain': Emoji.RAIN_CLOUD,
            'snow': Emoji.SNOW_CLOUD,
            'sleet': Emoji.RAIN_CLOUD,
            'wind': Emoji.WIND_BLOWING_FACE,
            'fog': Emoji.FOG,
            'cloudy': Emoji.CLOUD,
            'partly-cloudy-day': Emoji.PARTLY_SUNNY,
            'partly-cloudy-night': Emoji.PARTLY_SUNNY,
        }
        icon_default = Emoji.EARTH_AFRICA

        if data is None:
            api_key = get_darksky_api_key()
            lat = location['lat']
            lon = location['lon']
            data = requests.get(
                f'https://api.darksky.net/forecast/{api_key}/{lat},{lon}',
                params={
                    'exclude': 'minutely,alerts,flags',
                    'lang': 'en',
                    'units': units,
                }
            ).content
            redis.set(key, data, ex=5*60)

        result = json.loads(data.decode('utf-8'))

        temp_symbol = '℉' if units == 'us' else '℃'
        other_symbol = '℃' if units == 'us' else '℉'
        other_unit = 'si' if units == 'us' else 'us'

        return {
            'blocks': [
                {
                    'type': 'section',
                    'text': {
                        'type': 'mrkdwn',
                        'text': f'*Forecast for {location["display_name"]}*'
                    }
                },
                {
                    'type': 'actions',
                    'elements': [
                        {
                            'type': 'button',
                            'action_id': f'weather:{units}',
                            'text': {
                                'type': 'plain_text',
                                'text': (
                                    f'{Emoji.ARROWS_COUNTERCLOCKWISE} Refresh'
                                ),
                                'emoji': True
                            },
                            'value': str(query)
                        },
                        {
                            'type': 'button',
                            'action_id': f'weather:{other_unit}',
                            'text': {
                                'type': 'plain_text',
                                'text': f'to {other_symbol}'
                            },
                            'value': str(query)
                        }
                    ]
                },
                {
                    'type': 'divider'
                },
                {
                    'type': 'section',
                    'text': {
                        'type': 'mrkdwn',
                        'text': '*Current Weather*\n{summary}\n'
                            '{icon} {current_temperature}{temp_unit}\n'.format(
                                summary=result['hourly']['summary'],
                                icon=icon_map.get(
                                    result['currently']['icon'], icon_default),
                                current_temperature=int(
                                    result['currently']['temperature']),
                                temp_unit=temp_symbol,
                            ),
                    }
                },
                {
                    'type': 'divider'
                },
                {
                    'type': 'section',
                    'text': {
                        'type': 'mrkdwn',
                        'text': '*This Week*'
                    },
                    'fields': [
                        {
                            'type': 'mrkdwn',
                            'text': (
                                '*{day}*\n{icon} {high}{temp_unit} / '
                                '{low}{temp_unit}'.format(
                                    day=arrow.get(day['time']).format('ddd'),
                                    icon=icon_map.get(
                                        day['icon'], icon_default),
                                    high=int(day['temperatureHigh']),
                                    low=int(day['temperatureLow']),
                                    temp_unit=temp_symbol,
                                )
                            ),
                        }
                        for day in result['daily']['data']
                    ],
                },
                {
                    'type': 'context',
                    'elements': [
                        {
                            'type': 'mrkdwn',
                            'text': '<https://darksky.net/poweredby/|'
                                    'Powered by Dark Sky>'
                        }
                    ]
                }
            ]
        }
Ejemplo n.º 20
0
    def get_message_args(self, context: CommandContext):
        if len(context.args) == 1:
            (zip_code,) = context.args
            if not zip_code.isnumeric():
                return {"text": f"Zip code must be a number. Got `{zip_code}`"}
        elif len(context.args) > 1:
            return {"text": "Usage: `airquality [zipcode]`"}
        else:
            zip_code = get_default_zip_code()

        redis = get_redis()

        key = f"aqi:{zip_code}"
        data = redis.get(key)
        if data is None:
            airnow_api_key = get_airnow_api_key()
            observation_url = "http://www.airnowapi.org/aq/observation/zipCode/current/"
            data = requests.get(
                observation_url,
                params={
                    "API_KEY": airnow_api_key,
                    "distance": 25,
                    "zipCode": zip_code,
                    "format": "application/json",
                },
            ).content
            redis.set(key, data, ex=10 * 60)

        observations = json.loads(data.decode("utf-8"))

        # https://docs.airnowapi.org/aq101
        category_color_map = {
            1: "#00e400",  # Good - Green
            2: "#ffff00",  # Moderate - Yellow
            3: "#ff7e00",  # USG - Orange
            4: "#ff0000",  # Unhealthy - Red
            5: "#99004c",  # Very Unhealthy - Purple
            6: "#7e0023",  # Hazardous - Maroon
            7: "#000000",  # Unavailable - Black
        }

        parameter_map = {
            "PM2.5": "fine particulate matter",
            "PM10": "particulate matter",
            "O3": "ozone",
        }

        if len(observations) == 0:
            return {"text": f"No data available for `{zip_code}`"}

        return {
            "text": "Air Quality for {}, {}:".format(
                observations[0]["ReportingArea"], observations[0]["StateCode"]
            ),
            "attachments": [
                {
                    "title": "{} ({})".format(
                        observation["ParameterName"],
                        parameter_map[observation["ParameterName"]],
                    ),
                    "fallback": "{}\n{} - {}".format(
                        observation["ParameterName"],
                        observation["AQI"],
                        observation["Category"]["Name"],
                    ),
                    "color": category_color_map[observation["Category"]["Number"]],
                    "text": "{} - {}".format(
                        observation["AQI"], observation["Category"]["Name"]
                    ),
                    "footer": "Reported at {}{}:00 {}".format(
                        observation["DateObserved"],
                        observation["HourObserved"],
                        observation["LocalTimeZone"],
                    ),
                }
                for observation in observations
            ],
        }
Ejemplo n.º 21
0
 def __init__(self):
     redis = get_redis()
     self._access_token = _get_strava_access_token(redis)
Ejemplo n.º 22
0
    def get_message_args(self, context: CommandContext):
        if len(context.args) == 1:
            zip_code, = context.args
            if not zip_code.isnumeric():
                return {'text': f'Zip code must be a number. Got `{zip_code}`'}
        elif len(context.args) > 1:
            return {'text': 'Usage: `airquality [zipcode]`'}
        else:
            zip_code = get_default_zip_code()

        redis = get_redis()

        key = f'aqi:{zip_code}'
        data = redis.get(key)
        if data is None:
            airnow_api_key = get_airnow_api_key()
            observation_url = (
                'http://www.airnowapi.org/aq/observation/zipCode/current/')
            data = requests.get(observation_url,
                                params={
                                    'API_KEY': airnow_api_key,
                                    'distance': 25,
                                    'zipCode': zip_code,
                                    'format': 'application/json'
                                }).content
            redis.set(key, data, ex=10 * 60)

        observations = json.loads(data.decode('utf-8'))

        # https://docs.airnowapi.org/aq101
        category_color_map = {
            1: '#00e400',  # Good - Green
            2: '#ffff00',  # Moderate - Yellow
            3: '#ff7e00',  # USG - Orange
            4: '#ff0000',  # Unhealthy - Red
            5: '#99004c',  # Very Unhealthy - Purple
            6: '#7e0023',  # Hazardous - Maroon
            7: '#000000',  # Unavailable - Black
        }

        parameter_map = {
            'PM2.5': 'fine particulate matter',
            'PM10': 'particulate matter',
            'O3': 'ozone'
        }

        if len(observations) == 0:
            return {'text': f'No data available for `{zip_code}`'}

        return {
            "text":
            "Air Quality for {}, {}:".format(observations[0]['ReportingArea'],
                                             observations[0]['StateCode']),
            "attachments": [{
                "title":
                "{} ({})".format(
                    observation['ParameterName'],
                    parameter_map[observation['ParameterName']],
                ),
                "fallback":
                "{}\n{} - {}".format(observation['ParameterName'],
                                     observation['AQI'],
                                     observation['Category']['Name']),
                "color":
                category_color_map[observation['Category']['Number']],
                "text":
                "{} - {}".format(observation['AQI'],
                                 observation['Category']['Name']),
                "footer":
                "Reported at {}{}:00 {}".format(observation['DateObserved'],
                                                observation['HourObserved'],
                                                observation['LocalTimeZone'])
            } for observation in observations]
        }
Ejemplo n.º 23
0
    def get_message_args(self, context: CommandContext):
        redis = get_redis()
        if len(context.args) >= 1:
            query = " ".join(context.args)
        else:
            if redis.hexists(USER_LOCATION, context.event.user):
                query = redis.hget(USER_LOCATION, context.event.user).decode("utf-8")
            else:
                query = get_default_zip_code()

        location = get_location(query)
        if location is None:
            return {"text": f"Location `{query}` not found"}
        location_coords = (float(location["lat"]), float(location["lon"]))

        key = "purpleair"
        data = redis.get(key)
        if data is None:
            data = requests.get(PURPLEAIR_DATA_URL).content
            redis.set(key, data, ex=5 * 60)

        results = json.loads(data.decode("utf-8"))["results"]

        filtered_points = [
            point
            for point in results
            if (
                point.get("DEVICE_LOCATIONTYPE") == "outside"
                and "Lat" in point
                and "Lon" in point
                and point["AGE"] <= 30
            )
        ]
        child_points = {
            point["ParentID"]: point for point in results if "ParentID" in point
        }
        point_distances = (
            (point, distance((point["Lat"], point["Lon"]), location_coords))
            for point in filtered_points
        )
        point_distances = sorted(
            filter(lambda p_d: p_d[1].miles <= 25.0, point_distances),
            key=lambda p_d: p_d[1],
        )
        closest_points = point_distances[:3]
        if len(closest_points) == 0:
            return {
                "text": "No PurpleAir sensor within 25 miles of "
                f"{location['display_name']}"
            }

        def build_attachment(point, distance):
            pm25_10_min_avg = json.loads(point["Stats"])["v1"]
            flagged = "Flag" in point
            child_point = child_points.get(point["ID"])
            if child_point:
                pm25_10_min_avg = (
                    pm25_10_min_avg + json.loads(child_point["Stats"])["v1"]
                ) / 2
                flagged |= "Flag" in child_point

            for band in BANDS:
                lower_pm, upper_pm = band["pm25"]
                lower_aqi, upper_aqi = band["aqi"]
                color = band["color"]
                name = band["name"]
                if pm25_10_min_avg <= upper_pm:
                    # https://en.wikipedia.org/wiki/Air_quality_index#Computing_the_AQI
                    ten_min_aqi = (upper_aqi - lower_aqi) / (upper_pm - lower_pm) * (
                        pm25_10_min_avg - lower_pm
                    ) + lower_aqi
                    break

            return {
                "fallback": f"{ten_min_aqi} - {name}",
                "color": color,
                "text": f"{ten_min_aqi:.0f} - {name}",
                "footer": "{} | {:.1f} mi away | reported {:.0f} minutes ago".format(
                    point["Label"],
                    distance.miles,
                    (time.time() - point["LastSeen"]) / 60,
                ),
            }

        map_url = (
            "https://www.purpleair.com/map?opt=1/i/mAQI/a10/cC0#13.0/"
            f"{location_coords[0]}/{location_coords[1]}"
        )
        return {
            "text": f"PurpleAir sensors near <{map_url}|{location['display_name']}>:",
            "icon_emoji": ":purpleair:",
            "attachments": [
                build_attachment(point, distance) for point, distance in closest_points
            ],
        }
Ejemplo n.º 24
0
Archivo: tv.py Proyecto: pbhuss/meowbot
 def get_message_args(self, context: CommandContext):
     get_redis().incr("tvid")
     return {"text": "Refreshed tv!"}