zoukankan      html  css  js  c++  java
  • 【华为云技术分享】【IoT最佳实践】设备获取实时天气DEMO代码解读

    【摘要】 之前,我们曾为您介绍如何实现设备实时获取天气信息,本文将为您从代码逻辑层面解读该实时天气应用的DEMO。

    本文承接【IoT最佳实践】设备获取实时天气信息,为您解读实时天气DEMO的代码逻辑,助您开发自己的实时天气应用。

    业务逻辑

    在看代码之前,让我们先来了解下这个设备获取实时天气应用的业务逻辑。

    1577259798263576.png

    1. 首先,应用需要先向物联网平台订阅设备数据变化通知,这样设备上报数据时平台才会将数据推送至应用。

    2~3. 然后,设备需要向平台上报一条包含城市码的数据,平台将其推送至应用。

    4~5. 应用收到包含城市码的数据后,根据城市码查询查询城市名称,再查询对应城市的天气信息缓存。

    6~8. 若查询缓存未命中或者缓存中的天气信息已缓存了一个小时以上,则应用向气象平台查询最新的天气信息并写入缓存。

    9~10. 应用将天气信息通过物联网平台下发至设备。

    代码实现

    接下来让我们看下这个DEMO是如何用JAVA实现这个业务逻辑的。

    首先查看作为应用程序入口的Main函数。

    1 public static void main(String[] args) throws Exception {
    2    //------------调用订阅数据变化接口-------------------
    3    SubscribeDataChange.subscribe();
    4    System.out.println("正在搭建消息接收服务器。");
    5    //------------启动上报数据接收服务器-------------------
    6    SpringApplication.run(Main.class);
    7    System.out.println("消息接收服务器搭建完成。");
    8 }

    这个Main函数一共做了两件事,一是调用了物联网平台订阅借口订阅了设备数据变化,二是启动了一个消息接受服务器(基于SpringBoot框架)。

    订阅设备数据变化时,Main函数调用了SubscribeDataChange类的subscribe方法:

     1 public static void subscribe() throws Exception{
     2    /**---------------------initialize northApiClient------------------------*/
     3    NorthApiClient northApiClient = AuthUtil.initApiClient();
     4    SubscriptionManagement subscriptionManagement = new SubscriptionManagement(northApiClient);
     5    /**---------------------get accessToken at first------------------------*/
     6    Authentication authentication = new Authentication(northApiClient);
     7    AuthOutDTO authOutDTO = authentication.getAuthToken();
     8    String accessToken = authOutDTO.getAccessToken();
     9    /**---------------------sub deviceAdded notification------------------------*/
    10    //note: 10.X.X.X is a LAN IP, not a public IP, so subscription callbackUrl's IP cannot be 10.X.X.X
    11    String callbackUrl = PropertyUtil.getProperty("subscription_CallbackUrl");//this is a test callbackUrl
    12    SubscriptionDTO subDTO = subDeviceData(subscriptionManagement, "deviceDataChanged", callbackUrl, accessToken);
    13 }private static SubscriptionDTO subDeviceData(SubscriptionManagement subscriptionManagement, String notifyType, String callbackUrl, String accessToken) {
    14        SubDeviceDataInDTO sddInDTO = new SubDeviceDataInDTO();
    15        sddInDTO.setNotifyType(notifyType);
    16        sddInDTO.setCallbackUrl(callbackUrl);       try {
    17           SubscriptionDTO subDTO = subscriptionManagement.subDeviceData(sddInDTO, null, accessToken);
    18           System.out.println("上报数据订阅成功"+subDTO.toString());          return subDTO;
    19        } catch (NorthApiException e) {
    20           System.out.println("订阅接口已使用,若是重复订阅请忽略"+e.toString());
    21       }
    22       return null;
    23 }

    该方法通过华为云设备管理服务的北向应用的SDK完成了物联网平台的接入鉴权和设备数据变化通知的订阅。

    Main函数执行完之后,应用处于等待调用的状态,等待平台推送设备数据上来。

    当应用收到了平台推送的设备数据后,会调用handleDeviceDataChanged方法,这个方法由设备管理服务北向应用SDK定义,我们需要重写它来实现我们的业务逻辑。

     1 @Overridepublic void handleDeviceDataChanged(NotifyDeviceDataChangedDTO body) {
     2    String cityCode = body.getService().getData().get("areaCode").asText();
     3    //------------查询天气-------------------
     4    Map<String,Object>  apiBody = null;   try {
     5       apiBody = WeatherUtil.getApiBody(cityCode);
     6    } catch (IOException e) {
     7       e.printStackTrace();
     8    } catch (ParseException e) {
     9       e.printStackTrace();
    10    }try {
    11       System.out.println("正在下发命令给设备。");
    12       //------------调用下发命令接口-------------------
    13       InvokeDeviceService.invocation(apiBody);
    14    } catch (Exception e) {
    15       e.printStackTrace();
    16    }
    17    System.out.println("命令下发已完成。");
    18 }

    在这个方法中,应用首先通过城市码查询天气,然后将查询到的天气通过命令下发的方式的下发给设备。下发命令和订阅一样是通过调用设备管理服务北向应用SDK的接口实现,本文不再展开,让我们展开看下应用通过城市码查询天气的具体流程。

    1 public static Map<String,Object> getApiBody(String cityCode) throws IOException, ParseException {
    2     Map<String, String> cityCodeName = new HashMap<String, String>();
    3     cityCodeName.put("755", "深圳");
    4     cityCodeName.put("20", "广州");
    5     cityCodeName.put("10", "北京");
    6     cityCodeName.put("21", "上海");
    7     String cityName = cityCodeName.get(cityCode);
    8     System.out.println("接收到设备上报的数据,设备上报的cityCode是"+cityCode+",对应的城市名是"+cityName+"");

    首先应用根据城市码查询城市名。在这个DEMO中,我们现场构造了一个cityCodeName并写入了几大城市的城市码和城市名的对应关系,但在实际应用中,这个关系表应该是维护在持久化数据库中,此处从数据库中读取即可。

     1 File file=new File("cache/"+cityName+"dateTime"+".txt");
     2 Boolean isWeatherCur = false;if(!file.exists()){
     3     System.out.println("缓存没有天气数据,正在调用天气查询接口获取天气信息。");
     4     SimpleDateFormat sdf=new SimpleDateFormat("yy/MM/dd HH:mm:ss");
     5     String str=sdf.format(new Date());
     6     ReadWrTxt.writeFile(cityName+"dateTime",str);
     7 }else{
     8     String fileDateTime = ReadWrTxt.readFile(cityName+"dateTime");
     9     SimpleDateFormat format = new SimpleDateFormat("yy/MM/dd HH:mm:ss");
    10     String nowTime=format.format(new Date());
    11     Date d1 = format.parse(nowTime);
    12     Date d2 = format.parse(fileDateTime);    long diff = d1.getTime() - d2.getTime();    long diffMinutes = TimeUnit.MILLISECONDS.toMinutes(diff);    if(diffMinutes<=60 && diffMinutes>=0){
    13         System.out.println("读取缓存天气数据成功。");
    14         isWeatherCur = true;
    15     }else {
    16         System.out.println("天气数据缓存超过一个小时,已过期,正在调用天气查询接口获取天气信息。");
    17         SimpleDateFormat sdf=new SimpleDateFormat("yy/MM/dd HH:mm:ss");        String str=sdf.format(new Date());        ReadWrTxt.writeFile(cityName+"dateTime",str);    }}

    然后应用判断是否缓存过该城市的天气数据,以及缓存的时候是否已超过一个小时。此处我们采用比较简单做法,缓存是txt文件,文件名直接包括城市名,天气信息和缓存时间各保存一个文件。程序通过判断缓存时间txt文件是否存在判断是否缓存过天气信息,再读取缓存时间文件判断缓存是否超时。在您开发您自己的应用时,建议不要使用txt文件作为缓存,请使用redis之类的缓存数据库。

     1 File weatherFile=new File("cache/"+cityName+"weather"+".txt");
     2 Map<String,Object> apiBodySave = null;if(!weatherFile.exists()||!isWeatherCur){
     3     //------------调用天气查询接口,这里使用的是华为APIG SDK-------------------
     4     apiBodySave= Weather.getApiBody(cityName);
     5     String apiBodyStr = apiBodySave.toString();
     6     ReadWrTxt.writeFile(cityName+"weather",apiBodyStr);
     7 }
     8 String fileApiBodyStr = ReadWrTxt.readFile(cityName+"weather");
     9 fileApiBodyStr = fileApiBodyStr.replace("{","");
    10 fileApiBodyStr = fileApiBodyStr.replace("}","");
    11 fileApiBodyStr = fileApiBodyStr.replaceAll(" ","");
    12 String[] afterSplit = fileApiBodyStr.split(",");
    13 Map<String, Object> apiBody = new HashMap<String, Object>();for (String ele: afterSplit) {
    14     String[] keyVal = ele.split("=");
    15     keyVal[1]=keyVal[1].trim();
    16     apiBody.put(keyVal[0], keyVal[1]);
    17 }return apiBody;}

    若未缓存过该城市的天气信息或者缓存已过期,则通过华为云APIG调用气象平台的天气查询借口,并缓存天气信息。若已缓存过且天气信息未过期,则跳过该步骤,直接读取缓存的天气信息并返回。

    至此,设备获取实时天气的业务逻辑已打通,剩下的一些实现细节本文不再讲解,若您感兴趣,可以参考上一篇博客自行下载DEMO研究代码。

    作者:华为云专家 我是卤蛋

  • 相关阅读:
    Linux source命令
    pythoy 基础一: python的特点 if 语句 whlie语句
    linux 基础
    python的游戏之旅( 数字 字符串 列表 元组 字典 即为游戏职业)
    html 基础
    《SQL Server 2008 从入门到精通》 学习笔记 第五天
    [转载] Visual Studio 2010 MSDN Help Library文档位置、错误、重新安装及安装注意事项
    ASP.NET后台通过输出JavaScript弹出窗口小结
    网上搜集的webbrower的资料,很有借鉴价值
    解决MSSQL 2008不能用IP登录的问题 和 打开可以用SA登录SQL2008的方法
  • 原文地址:https://www.cnblogs.com/huaweicloud/p/12525874.html
Copyright © 2011-2022 走看看