mcpField
P
pikud-haoref-alerts

pikud-haoref-alerts

github.com/yaniv-golan其他2145 次安装34 周前更新
代码仓库

关于 pikud-haoref-alerts

pikud-haoref-alerts 是关于以色列本土防卫司令部警报 API 的开发技能,面向构建警报监控和数据应用的开发者。它整理实时与历史端点、警报类别、数据限制及替代来源,并提醒官方 API 可能存在地理封锁。

主要功能

  1. 01整理官方实时与历史端点
  2. 02说明警报类别及结束信号
  3. 03涵盖预警匹配与状态判断
  4. 04比较历史数据来源和限制
  5. 05说明地理封锁及应对方式

适用场景

  1. 01轮询实时警报并发送通知
  2. 02判断特定地点的警报是否仍有效
  3. 03分析预警与后续警报的关联
  4. 04规划警报历史数据的采集

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/yaniv-golan/pikud-haoref-alerts --skill pikud-haoref-alerts

安装后在 Claude Code 中输入/pikud-haoref-alerts确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
alternative-data-sources.md
common-patterns.md
community-libraries.md
mcp-and-homeassistant.md

详细介绍

Pikud HaOref 警报 API

本技能涵盖使用 Pikud HaOref(以色列国土防卫司令部)警报系统所需了解的一切——从官方原始端点到社区封装库和部署策略。

详细参考资料请见 references/ 目录:

  • references/community-libraries.md — Node.js、Python、C#、Docker 封装库
  • references/mcp-and-homeassistant.md — 用于 AI 集成的 MCP 服务、Home Assistant 配置
  • references/common-patterns.md — 轮询循环、通知机器人、仪表板、地图、历史归档、多地点监控、智能家居、无障碍访问
  • references/alternative-data-sources.md — Tzofar(tzevaadom.co.il)API、oref 到 Tzofar 的类别映射、社区归档项目

重要限制:地理封锁

官方 oref.org.il API 可能会屏蔽非以色列 IP 地址。这是意外出现 403 错误最常见的原因。该屏蔽似乎基于 CDN/Akamai,且不一定会一致地应用于所有非以色列 IP——在搭建代理基础设施之前,请先尝试访问你的端点。Tzofar(tzevaadom.co.il)端点不受地理封锁,可从任何 IP 访问。

**被屏蔽时的解决方法:**在 GCP me-west1(特拉维夫)VM 上部署。注意:e2-micro 在 me-west1 不符合免费套餐资格(免费套餐仅限部分美国区域),但它是获取以色列 IP 最便宜的选择。

gcloud compute instances create pikud-haoref \
  --zone=me-west1-a \
  --machine-type=e2-micro \
  --image-family=debian-12 \
  --image-project=debian-cloud \
  --tags=http-server

gcloud compute firewall-rules create allow-pikud-haoref \
  --allow=tcp:8000-8002 --target-tags=http-server

官方端点

Pikud HaOref 未发布正式的 API 文档。以下端点是根据官方网站和移动应用逆向分析得出的,多年来一直保持稳定。它们返回 JSON(有时带有需要剥除的 UTF-8 BOM)。

实时警报
GET https://www.oref.org.il/warningMessages/alert/alerts.json

返回当前生效的警报;若没有生效的警报,则返回空响应。必须进行轮询——通常每 1–2 秒轮询一次,以实现实时响应。

重要:这是一个快照,不是状态检查。只有在警报期间警笛正在鸣响时,端点才会短暂显示警报(通常为数秒至一分钟)。空响应并不表示“警报解除”——这只表示此刻没有警笛鸣响。要判断某种情况是否仍在持续,还必须检查历史端点,确认最近的警报是否没有与之匹配的类别 13“事件结束”消息(见下文判断某种情况是否仍在持续)。

警报生效时的响应:

{
  "id": "134168709720000000",
  "cat": "1",
  "title": "ירי רקטות וטילים",
  "data": ["תל אביב - מרכז העיר", "רמת גן - מערב"],
  "desc": "היכנסו למרחב המוגן ושהו בו 10 דקות"
}

字段:

  • id — 唯一警报标识符(数字字符串)。可用于去重。
  • cat — 类别编号(见下方的警报类别)。
  • title — 以希伯来语表示的易读警报类型。
  • data — 受影响地点名称的数组,名称为希伯来语。
  • desc — 以希伯来语表示的防护指示。

**无警报时的响应:**空响应正文(可能仅包含 BOM)。

**建议的请求头:**该端点无需特殊请求头即可使用,但发送类似浏览器的请求头可降低被屏蔽的概率:

Referer: https://www.oref.org.il/
X-Requested-With: XMLHttpRequest
警报历史记录(JSON 文件——高负载时不可靠)
GET https://www.oref.org.il/warningMessages/alert/History/AlertsHistory.json

返回最近的警报记录,最多 3,000 条,且不支持分页。活动较少时,数据可能涵盖数周;在冲突激烈时,一天内的记录就可能超过 3,000 条(例如,1,147 条预警 + 483 条导弹警报 + 22 条飞机警报 + 1,348 条结束通知 = 恰好 3,000 条)。可用于补查两次轮询之间可能错过的警报,但在局势升级期间,不适合用于可靠的历史分析。

高负载时的性能下降: 在警报量大的时期(冲突活跃期间),AlertsHistory.json 可能返回 HTTP 200,但响应正文为空(约 2 字节);与此同时,GetAlarmsHistory.aspx 仍会返回完整数据(600 KB 以上)。请优先使用 GetAlarmsHistory.aspx 作为主要历史数据源,并将 AlertsHistory.json 作为备用。

重要: 不含 /alert/ 路径段的路径(例如 /warningMessages/History/AlertsHistory.json)会返回 403。路径大小写不敏感——/WarningMessages/ 和 /warningMessages/ 均可用——但必须包含 /alert/ 路径段。

响应格式:

[
  {
    "alertDate": "2024-10-15 14:32:00",
    "title": "ירי רקטות וטילים",
    "data": "אשדוד - א,ב,ד,ה",
    "category": 1
  }
]

请注意,此处的 data 是字符串(而非实时端点返回的数组),且 category 是数字(而非字符串)。

警报历史记录(推荐)
GET https://alerts-history.oref.org.il/Shared/Ajax/GetAlarmsHistory.aspx?lang=he&mode=1

这是一个位于专用子域名上的 ASP.NET 端点,可返回更丰富的历史数据,包括 matrix_id、rid 和 category_desc 字段。可作为备用,或在需要额外元数据时使用。支持 lang=he(希伯来语)和 lang=en(英语)。

同样受 3,000 条记录上限约束。 mode 参数接受 1–3 的值(模式 4–5 返回空结果),但所有模式均返回最近的 3,000 条记录。不支持按日期范围查询。这并非分页机制。

不同历史端点的日期格式:

  • AlertsHistory.json:"alertDate": "2026-03-06 19:33:53"(以空格分隔,包含秒)
  • GetAlarmsHistory.aspx:"alertDate": "2026-03-06T19:35:00"(使用 ISO 8601 的 T 分隔符,秒始终为 :00)
警报类别
GET https://www.oref.org.il/alerts/alertCategories.json

返回由对象组成的类别元数据,包含 id、category(字符串标识名)、matrix_id、priority 和 queue 字段。注意:响应不会直接将类别编号对应到希伯来语名称——下表根据实时警报数据整理而成,并非仅根据此端点得出。已知类别如下:

类别类型希伯来语
1导弹 / 火箭ירי רקטות וטילים
2敌对飞机入侵חדירת כלי טיס עוין
3地震רעידת אדמה
4海啸צונאמי
5放射性事件אירוע רדיולוגי
6危险物质חומרים מסוכנים
7恐怖分子渗透חדירת מחבלים
13事件结束האירוע הסתיים
14预警 / 即将发出警报的通知בדקות הקרובות צפויות להתקבל התרעות באזורך

类别 101–107 分别对应类别 1–7 的演习版本。

类别 13:事件结束

当 Pikud HaOref 确定某地点的威胁已解除时,会发送类别 13 警报,标题为「האירוע הסתיים」(事件已结束)或「ניתן לצאת מהמרחב המוגן」(可以离开避难空间)。这是特定警报事件已结束的权威信号。此类警报会按地点显示在历史端点中。

类别 14:预警(即将发出警报的通知)

类别 14 警报的标题为「בדקות הקרובות צפויות להתקבל התרעות באזורך」,用于提醒某区域未来几分钟内预计会收到警报。这是即将发生袭击的早期预警,可提供标准避难倒计时之外的准备时间。如果预警在约 20 分钟内没有升级为实际警报(类别 1–7),则可视为已过期。

将预警与实际警报匹配

一项常见的分析任务是确定哪些预警(cat 14)升级成了实际警报(cat 1–7)。难点在于:不同类别的地点名称字符串有时无法准确匹配,而且一条预警之后可能会出现多条警报。

from datetime import timedelta

def match_prealerts_to_alerts(history, source="oref_history", window_minutes=20):
    """Match cat 14 pre-alerts to subsequent cat 1-7 alerts by location overlap.

    Uses normalize_alert_time() for proper datetime comparison.
    Returns list of (prealert, [matching_alerts]) tuples.
    """
    prealerts = [e for e in history if e.get("category") == 14]
    alerts = [e for e in history if e.get("category") in (1, 2, 3, 4, 5, 6, 7)]
    window = timedelta(minutes=window_minutes)
    matches = []

    for pa in prealerts:
        pa_time = normalize_alert_time(pa["alertDate"], source)
        pa_locations = pa.get("data", "")
        matched = []
        for a in alerts:
            a_time = normalize_alert_time(a["alertDate"], source)
            if a_time <= pa_time or a_time > pa_time + window:
                continue
            a_locations = a.get("data", "")
            # Token overlap: handles partial location name matches
            pa_words = set(pa_locations.replace(",", " ").split())
            a_words = set(a_locations.replace(",", " ").split())
            if pa_words & a_words:
                matched.append(a)
        matches.append((pa, matched))

    return matches

注意: cat 14 和 cat 1 中的地点名称字符串不总是完全一致——cat 14 通常使用区域/地带名称,而 cat 1 使用具体城市名称。与精确匹配相比,子字符串或词元重叠匹配效果更好。20 分钟的时间窗口反映了预警升级为警报的典型耗时;请根据观察到的模式进行调整。

判断情况是否仍在持续

不要仅凭 alerts.json 为空就作出判断。 实时端点只是一个时间范围很窄的快照——警报会在几秒内消失。正确的做法是进行双重检查:

  1. 检查 alerts.json,查看即时快照(此刻是否正在响警报?)
  2. 检查历史记录端点,查看该地点近期是否出现 cat 1–7 警报
  3. 检查该地点的警报之后是否出现匹配的 cat 13“事件结束”消息
  4. 如果尚未收到 cat 13 → 情况仍在持续
def is_situation_active(location_hebrew, history):
    """Check if a location still has an active alert (no cat 13 received yet)."""
    last_alert_time = None
    last_concluded_time = None

    for entry in history:
        if location_hebrew not in entry.get("data", ""):
            continue
        cat = entry.get("category", 0)
        alert_time = entry.get("alertDate", "")
        if cat in (1, 2, 3, 4, 5, 6, 7):
            if last_alert_time is None or alert_time > last_alert_time:
                last_alert_time = alert_time
        elif cat == 13:
            if last_concluded_time is None or alert_time > last_concluded_time:
                last_concluded_time = alert_time

    if last_alert_time is None:
        return False  # no recent alert
    if last_concluded_time is None:
        return True   # alert with no conclusion yet
    return last_alert_time > last_concluded_time  # alert after last conclusion
历史数据策略

两个官方历史记录端点都限制为 3,000 条记录,因此需要根据时间跨度使用不同的数据源:

需求来源备注
最近几分钟alerts.json(实时)每 1–2 秒轮询一次
最近约 3,000 条记录(所有类别)AlertsHistory.json 或 GetAlarmsHistory.aspx包含预警和已结束事件;覆盖数小时至数周,视活动情况而定
最近 50 个警报组(不含预警)api.tzevaadom.co.il/alerts-history无地理区域限制
数月/数年(不含预警)从后往前遍历 Tzofar 警报组 ID无地理区域限制;注意速率限制(参见 references/alternative-data-sources.md)
完整历史记录(含预警)自行持续轮询不存在追溯数据源——必须在所需时段开始前就运行轮询程序

预警历史记录缺口(关键限制): 预警数据(cat 14)和事件结束消息(cat 13)没有追溯数据源。Tzofar 完全不包含这些数据。官方 oref 历史记录端点虽然包含这些数据,但上限为 3,000 条记录。在冲突活跃期间,这 3,000 条记录可能只覆盖数小时。如果需要预警历史数据,必须在要分析的时段开始前设置自己的持续轮询程序。 事后无法恢复这些数据。社区存档(hasadna、Meir017)也不包含预警,除非其特定抓取程序会采集这些数据。

合并 oref 和 Tzofar 数据: 分析持续多日的冲突时,通常需要同时使用这两个来源。主要对齐要点:(1) 统一时间戳格式——oref 使用以色列当地时间字符串,Tzofar 使用 Unix 时间戳(UTC);(2) 使用 references/alternative-data-sources.md 中的类别映射表对齐威胁类型;(3) 按时间戳和城市名称进行匹配去重,因为两个来源报告的是相同的底层警报。

from datetime import datetime, timezone
from zoneinfo import ZoneInfo  # stdlib in Python 3.9+

IST = ZoneInfo("Asia/Jerusalem")  # handles DST automatically

def normalize_alert_time(raw, source):
    """Normalize any alert timestamp to a Python datetime in Israel time.

    source: 'oref_history' | 'oref_aspx' | 'tzofar'
    """
    if source == "oref_history":
        # "2026-03-07 19:33:53" (space-separated, Israel local time)
        return datetime.strptime(raw, "%Y-%m-%d %H:%M:%S").replace(tzinfo=IST)
    elif source == "oref_aspx":
        # "2026-03-07T19:35:00" (ISO T-separator, Israel local time)
        return datetime.strptime(raw, "%Y-%m-%dT%H:%M:%S").replace(tzinfo=IST)
    elif source == "tzofar":
        # Unix timestamp (UTC)
        return datetime.fromtimestamp(raw, tz=timezone.utc).astimezone(IST)

oref 类别到 Tzofar 威胁类型的映射: 同时使用这两个数据源时,请注意数字 ID 并不相同。完整映射表请参见 references/alternative-data-sources.md。


何时使用原始端点,何时使用库

默认使用原始端点。 官方 JSON 文件简单、稳定,且有明确说明。对于大多数使用场景——轮询警报、查看历史记录、构建通知服务——直接发送 HTTP 请求就够了。

当库能提供你本来需要自行维护的数据时,再使用库。 最常见的原因是 cities.json 数据库——它包含约 1,500 个地点,以及这些地点的希伯来语/英语/俄语/阿拉伯语名称、GPS 坐标、区域映射和前往避难所所需的时间。各个库的详情请参见 references/community-libraries.md。


特定地点查询

一个非常常见的用例是检查某个城市或地区是否有正在生效的警报。难点在于,官方 API 返回的地点名称是希伯来语,但用户通常会用英语或希伯来语转写名称提问。

城市数据库

pikud-haoref-api Node.js 库附带一个全面的 cities.json 文件(可在 https://github.com/eladnava/pikud-haoref-api 获取),用于映射所有可能触发警报的地点。每个条目包含:

{
  "id": 511,
  "name": "אבו גוש",
  "name_en": "Abu Ghosh",
  "name_ru": "Абу Гош",
  "name_ar": "أبو غوش",
  "zone": "שפלת יהודה",
  "zone_en": "Judean Lowlands",
  "lat": 31.80686,
  "lng": 35.11038,
  "countdown": 90,
  "value": "אבו גוש"
}

关键字段:name/name_en 用于匹配,zone/zone_en 用于区域查询,countdown 表示到达避难所的时间(秒),lat/lng 用于计算邻近地点和显示地图,value 用于与警报 data 数组中的内容匹配。

匹配策略

data 数组中的警报地点名称不一定与城市名称完全一致。地点可能显示为 "תל אביב - מרכז העיר",而不只是 "תל אביב"。有三种策略:

  1. 子串匹配 — "תל אביב" in "תל אביב - מרכז העיר" → True。简单,适用于大多数情况。
  2. 模糊匹配 — 使用 fuzzywuzzy 或类似工具,阈值设为约 60-70。可处理不同的转写形式。
  3. 按区域匹配 — 根据 zone/zone_en 匹配,以支持范围更广的区域查询。
英语到希伯来语名称解析

当用户用英语询问某个城市时,将其解析为希伯来语 value:

  • 查询 cities.json — 搜索 name_en。这是最可靠的方法。
  • 英语模糊搜索 — “Gan Hayim”、“Gan Chaim”、“Gan Hayyim”均对应 גן חיים。
  • 多语言支持 — 还提供 name_ru 和 name_ar。
基于邻近程度的查询

使用城市数据库中的 lat/lng 坐标:

from math import radians, cos, sin, asin, sqrt

def haversine(lat1, lon1, lat2, lon2):
    """Distance in km between two GPS coordinates."""
    lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2])
    dlat, dlon = lat2 - lat1, lon2 - lon1
    a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
    return 2 * 6371 * asin(sqrt(a))

def cities_near(lat, lon, radius_km, cities_db):
    return [c for c in cities_db
            if haversine(lat, lon, c["lat"], c["lng"]) <= radius_km]
到达避难所的时间

每个地点都有一个 countdown 值(秒)。范围从 0 秒(靠近加沙的边境社区)到 90 秒。报告特定地点的警报时,务必包含此信息——它关系到生命安全。


示例

示例 1:“为我构建一个用于火箭弹警报的 Telegram 机器人”

  • 事先说明地理封锁限制
  • 使用 references/common-patterns.md 中的轮询循环模式
  • 在 on_new_alert 回调中添加 Telegram sendMessage
  • 建议部署到 GCP me-west1
  • 结果:一个可向 Telegram 聊天发送警报的可用机器人

示例 2:“阿什凯隆现在有警报吗?”

  • 加载 cities.json——注意,阿什凯隆有子区域:“Ashkelon - North”(אשקלון - צפון)和 “Ashkelon - South”(אשקלון - דרום),每个区域的倒计时均为 30 秒
  • 双重检查:轮询 alerts.json,并检查历史记录中是否有近期的 cat 1–7 警报且没有匹配的 cat 13
  • 对警报 data 字段进行“אשקלון”子串匹配,以涵盖所有子区域
  • 报告结果,包括避难时间(阿什凯隆为 30 秒)
  • 如果 alerts.json 为空,但历史记录显示近期有警报且没有 cat 13,则说明情况仍在持续

示例 3:“搭建一个实时警报地图仪表板”

  • 服务端:轮询循环 → 通过 SSE 或 WebSocket 扇出(参见 references/common-patterns.md)
  • 客户端:Leaflet.js + OpenStreetMap,使用 cities.json 中的坐标设置标记
  • 为标记补充区域和倒计时数据
  • 不要让浏览器直接轮询 oref.org.il

示例 4:“将警报集成到 Home Assistant”

  • 指向 oref_alert HACS 集成(参见 references/mcp-and-homeassistant.md)
  • 根据 HA 的家庭位置自动配置
  • 提供 sensor.oref_alert 和 _time_to_shelter 实体
  • 常见自动化操作:闪烁灯光、锁门、暂停媒体、通过扬声器播报

示例 5:“分析过去一周冲突期间的警报模式”

  • 首先询问:是否需要预警(cat 14)?如果需要,则必须自行归档轮询数据——没有可追溯的历史数据源
  • 仅针对实际威胁警报:以保守的节奏(延迟 1–2 秒)倒序遍历 Tzofar 警报组 ID
  • 对于最新数据(如果在 3,000 条记录以内):使用包含所有类别的 GetAlarmsHistory.aspx
  • 使用 references/alternative-data-sources.md 中的类别映射,将 Tzofar 和 oref 数据规范化为通用模式
  • 使用 cities.json 补充坐标,并添加区域数据以进行地理分析

注意事项和故障排查

  1. UTF-8 BOM — 官方端点有时会在 JSON 前返回 BOM(\ufeff)。务必将其移除:text.lstrip('\ufeff')。
  2. 空响应与无警报 — 响应正文为空表示当前没有活动警报。不要将其解析为 JSON。
  3. 历史记录损坏 — 历史记录端点偶尔会返回格式错误的 JSON。几秒后重试。
  4. 速率限制 — 实时监控时,每隔 1–2 秒轮询一次。更频繁地轮询没有帮助,还可能导致你被封锁。
  5. 希伯来语编码 — 所有地名和描述均为希伯来语。请在整个技术栈中使用 UTF-8。
  6. 多个同时发生的警报 — 大规模袭击期间,可能同时出现多种警报类型。你的代码应处理数组,而不是假设只有单条警报。
  7. 演习警报 — 类别 101–107 为演习警报。除非你明确需要,否则请将其过滤掉。
  8. 3,000 条记录上限 — AlertsHistory.json 和 GetAlarmsHistory.aspx 都硬性限制为 3,000 条记录,且不支持分页或按日期范围筛选。在 2026 年 3 月的冲突期间,约 97 分钟就耗尽了 3,000 条记录(854 条预警 + 480 条导弹警报 + 38 条飞机警报 + 1,628 条警报结束记录)。GetAlarmsHistory.aspx 上的 mode=1,2,3 参数不提供分页功能——所有模式都返回最近的相同 3,000 条记录(mode=4,5 返回空结果)。如需更深入的历史记录,请使用 Tzofar 的存档或社区轮询器(参见 references/alternative-data-sources.md)。
  9. 以色列时区 — 所有 oref 时间戳均为以色列当地时间(Asia/Jerusalem;使用 zoneinfo.ZoneInfo("Asia/Jerusalem") 自动处理夏令时)。Tzofar 使用 Unix 时间戳(UTC)。合并来源或按日期分组时,请先统一时区。
  10. 403 Forbidden — 两个常见原因:(a)地理封锁——从以色列 IP(GCP me-west1)部署或使用代理,不过并非所有非以色列 IP 都会被封锁;(b)缺少 /alert/ 路径段——例如,/warningMessages/History/AlertsHistory.json 会返回 403,而 /warningMessages/alert/History/AlertsHistory.json 可以正常工作。路径大小写不敏感。

评论

支持 Markdown