改造CIMISS MUSIC接口的Python SDK

目录

本文仅代表笔者对 2019 年 10 月时 MUSIC 接口发布版本的观点,随着版本更新及对接口进一步研究,笔者后续观点已有变化。

注:CMADaaS 已提供官方 Python 3 的 MUSIC 接口。

2021.04.15

背景

CIMISS 是全国综合气象信息共享平台 (China Integrated Meteorological Information Service System) 的简称。 由国家气象信息中心牵头建设,用于共享气象业务的数据信息。 对于数值预报中心来说,CIMISS 一般用于检索观测资料。

MUSIC 接口是气象数据统一服务接口 (MUSIC:Meteorological Unified Service Interface Community) 的简称,是为访问 CIMISS 库中保存的数据而开发的接口。 该接口提供统一、标准、丰富的数据访问服务和应用编程接口 (API),为应用系统提供唯一权威的数据接入服务。

今年 6 月 30 日开放测试的 气象大数据云平台 看起来像是对 CIMISS 系统的升级,不仅包含数据,提供包括内置算法在内的计算功能。 该平台提供了 MUSIC 2.0 版的接口。

MUSIC接口的版本

当前业务系统正在使用的 MUSIC 接口版本是1.6,从 MUSIC接口内网网址 下载。

2.0 版本与 1.6 版本最大的区别在于使用不同的库实现数据序列化。 1.6 版本使用 ICE,2.0 版本使用 Protobuf

MUSIC 1.6 版本只提供了 Python 2.6 的 SDK,而没有提供更广泛使用的 Python 2.7 版本。所以我没有使用过这个版本的 SDK。

MUSIC 2.0 版本提供了 Python 2.7 的 SDK,却没有提供 Python 3.x 版本。 Python 2.7 版本将于 2020 年停止维护,所以我觉得现在发布的 Python 库都支持 Python 3.x 版本。

注:CMADaaS 已提供官方 Python 3 的 MUSIC 接口。[2021.04.15]

不过好在 Protobuf 生成的 Python 代码同时支持 Python 2 和 3,我花了一些时间将整个 MUSIC Python SDK 移植到 Python 3。

修改代码过程中,发现 MUSIC Python SDK 库的代码不像是熟悉 Python 的程序员编写的,编码方式有一些 C/C++ 的风格。 从而萌生了重新写一个 MUSIC Python SDK 的想法。

下面介绍经过重新设计的SDK库 —— nuwe-cimiss-python

起步

重写的第一步就是编写 protobuf 的定义文件。 Python 这类脚本语言的优势在于不容易隐藏源码,可以从 Python SDK 中的 apiinterface_pb2.py 文件反推回 protobuf 定义文件。

MUSIC 的 protobuf 仅使用基础功能,所以很容易就能得到 proto 文件。

syntax = "proto3";

package cma.music.pb;

message RequestInfo{
    int32 errorCode = 1;
    string errorMessage =2;
    string requestElems = 3;
    string requestParams = 4;
    string requestTime = 5;
    string responseTime = 6;
    int32 rowCount = 7;
    int32 takeTime = 8;
    int32 colCount = 9;
}

message RetArray2D{
    repeated string data = 1;
    RequestInfo request = 2;
    repeated string elementNames = 3;
}

message RetGridArray2D{
    repeated float data = 1;
    RequestInfo request = 2;
    float startLat = 3;
    float startLon = 4;
    float endLat = 5;
    float endLon = 6;
    int32 latCount = 7;
    int32 lonCount = 8;
    float lonStep = 9;
    float latStep = 10;
    repeated float lats = 11;
    repeated float lons = 12;
    string units = 13;
    string userEleName = 14;
}

message FileInfo{
    string fileName = 1;
    string savePath = 2;
    string suffix = 3;
    string size = 4;
    string fileUrl = 5;
    string imgBase64 = 6;
    repeated string attributes = 7;
}

message RetFilesInfo{
    repeated FileInfo fileInfos = 1;
    RequestInfo request = 2;
}

message StoreArray2D{
    repeated string data = 1;
    int32 row = 2;
    int32 col = 3;
    int32 fileflag = 4;
    repeated string filenames = 5;
    int32 is_backstage = 6;
    string client_mount_path = 7;
    string server_mount_path = 8;
}

message RetDataBlock{
    string dataName = 1;
    bytes byteArray = 2;
    RequestInfo request = 3;
}

message RetGridVector2D{
    repeated float u_datas = 1;
    repeated float v_data2 = 2;
    RequestInfo request = 3;
    float startLat = 4;
    float startLon = 5;
    float endLat = 6;
    float endLon = 7;
    int32 latCount = 8;
    int32 lonCount = 9;
    float lonStep = 10;
    float latStep = 11;
    repeated float lats = 12;
    repeated float lons = 13;
    string u_EleName = 14;
    string v_EleName = 15;
}

message RetGridScalar2D{
    repeated float datas = 1;
    RequestInfo request = 2;
    float startLat = 3;
    float startLon = 4;
    float endLat = 5;
    float endLon = 6;
    int32 latCount = 7;
    int32 lonCount = 8;
    float lonStep = 9;
    float latStep = 10;
    repeated float lats = 11;
    repeated float lons = 12;
    string units = 13;
    string userEleName = 14;
}

message StoreGridData{
    repeated string attributes = 1;
    int32 pointflag = 2;
    repeated float Lats = 3;
    repeated float Lons = 4;
    repeated float datas = 5;
}

message StoreBlockData{
    repeated string attributes = 1;
    bytes data = 2;
}

使用新的 proto 文件编译 python 代码,会发现与之前的代码有所不同。 不过经测试发现,不影响对消息的解析,可以正常使用。

架构

CIMISS MUSIC 接口调用包括下面几个步骤:

  • 根据用户提供的参数和接口生成相应的URL
  • 访问 URL 获取响应
  • 对响应进行解析,包括错误处理和 protobuf 反序列化
  • 对响应进行本地操作,可选步骤

整个 API 的架构如下所示:

account
account
server config
server config
interface id
interface id
interface params
interface params
CimissClient
CimissClient
generate url
generate url
request
request
parse response
parse response
local operation
local operation

不过我这里要指出的是,MUSIC 接口在 URL 中使用明文传输密码,即使在内网也充满风险。 不过这不是我能接触到范畴,所以还是当做没看见比较好。

注:2020 年新版 MUSIC 接口已不再使用明文密码传输。 2021.04.15

使用

MUSIC 接口仅适用于气象局内网用户,使用前请先申请账户。

使用 nuwe_cimiss.CimissClient 类从 CIMISS 中检索数据。

需要提供 CIMISS 服务的相关参数,可以保存在当前目录 client.conf 文件中, 或者在创建 nuwe_cimiss.CimissClient 对象显式指定。参数包括:

  • music_server: MUSIC 接口 ip 地址,必须指定
  • music_port:MUSIC 接口端口号,必须指定
  • music_connTimeout:连接超时,秒,可选
  • music_readTimeout:数据读取超时,秒,可选
  • music_ServiceId:默认服务节点 id

下面的示例展示如何检索地面观测资料。

from nuwe_cimiss import CimissClient

client_config_path="path/to/client/config/file"
user="user name"
password="user password"
server_id = "server id"

interface_id = "getSurfEleByTimeRange"

params = {
    "dataCode": "SURF_CHN_MUL_HOR",
    "elements": "Station_Id_d,Lat,Lon,Alti,Day,Hour,PRS_Sea,TEM,"
    "DPT,WIN_D_INST,WIN_S_INST,PRE_1h,PRE_6h,PRE_24h,PRS",
    "timeRange": "[20190817000000,20190817020000)",
    "orderby": "Station_ID_d:ASC",
    "limitCnt": "10",
}

client = CimissClient(
    user=user,
    password=password,
    config_file=client_config_path
)
result = client.callAPI_to_array2D(interface_id, params)

参考

perillaroc/nuwe-cimiss-python

perillaroc/nuwe-cimiss-cpp