【个人开发】开发一个每天早上向我发送电力费用的Line Bot,以GraphQL API作为请求方式【第一部分】

起初,首先.

由于我目前使用的Octopus Energy提供了GraphQL API,我打算利用它开发一个每天早上都能收到电费通知的Line Bot。

这一次我们将会讲解Rails与外部API的集成、GraphQL的使用方法以及如何运用Line Messaging API。
关于定期运行和部署,我们计划在下一篇文章中写(尚未实施)。

如果想知道GraphQL到底是什么的话,请查看下面的文章。

 

利用技术

Rails(API模式):7.0.8
Ruby:3.2.0
graphql 2.0.27
Line Messaging API

实施策略

1.使用Rails调用GraphQL获取电费信息
2.利用Line Messaging API将获取的电费信息发送给用户
— 这次的任务到这里结束 —
3.在开发环境中创建定期执行的任务
4.确保在生产环境中能够定期执行

让Rails通过GraphQL获取并返回电费信息

在使用Octopus Energy获取电费的步骤如下:
1.注册Otopus Energy账户。
2.开始使用Octopus Energy供电。

1-1. 使用电子邮件和密码作为查询变量,获取认证令牌(变更)。
1-2. 使用认证令牌获取电费信息(查询)。

使用Mutation和Query的区别

基本上,它大致上將按照下圖的組合使用來區分。

    • RESTとはRepresentational State Transferの略でwebサービスの設計モデルのこと

 

    • SQLとはデータベース用のクエリ言語のこと

 

    GraphQLとはAPIのクエリ言語のこと
RestSQLGraphQLデータ取得GETSelectQueryデータ追加POSTCreateMutationデータ更新PATCHUpdateMutationデータ削除DELETEDeleteMutation

如果把数据获取称为Query,其他操作称为Mutation,这样可能更容易记忆(另外,事件监控称为Subscription)。

准备事项

在安装 Rails 应用之前,需要通过添加以下 gem 并执行 bundle install 使 Graphql 在 Rails 应用中可用。

gem 'graphql'
gem 'graphql-client'
gem 'dotenv-rails'

graphql-client是一个用于声明、创建和执行GraphQL查询的Ruby库。

请参阅以下内容以获取更详细信息。

 

dotenv-rails是一个用于管理环境变量的Ruby库。通过在应用程序的根目录下创建.env文件,可以处理不希望在网络上公开的机密密钥和密码等信息,并且可以自动加载这些信息。

OCTOPUS_EMAIL = "XXX@example.com"
OCTOPUS_PASSWORD = "passwordhogefuga"

可以这样定义:
调用时,可以通过类似 ENV[“OCTOPUS_EMAIL”] 的形式进行调用!

为了隐藏文件,请确保设置了.gitignore文件,以防忘记。

请查看以下详细内容。

 

1-1. 使用电子邮件和密码作为查询变量,获取认证令牌。

在进行了上述的安装之后,为了获取令牌,请创建以下文件。

由于对于graphql-client的补充说明很少,因此我将在注释中进行说明。

require "graphql/client"
require "graphql/client/http"

class OctopusAuthenticationToken
  # http アダプターを設定
  HTTP = GraphQL::Client::HTTP.new("https://api.oejp-kraken.energy/v1/graphql/")

  # 上記を使用して、API サーバーから GraphQL Schema を取得
  Schema = GraphQL::Client.load_schema(HTTP)

  # 上記を使ってクライアント作成
  Client = GraphQL::Client.new(schema: Schema, execute: HTTP)

  # ログイントークンを作成する,mutationを定義
  LOGIN_QUERY = self::Client.parse <<~GRAPHQL
    mutation($input: ObtainJSONWebTokenInput!) {
      obtainKrakenToken(input: $input) {
        token
        refreshToken
      }
    }
  GRAPHQL

  def generate_token
    # mutationを実行してその実行結果をresultに格納する
    result = Client.query(LOGIN_QUERY, variables: {
      input: {
        email: ENV["OCTOPUS_EMAIL"],
        password: ENV["OCTOPUS_PASSWORD"],
      },
    })
    result.original_hash.dig("data", "obtainKrakenToken", "token")
  end
end

我們在上面進行了以下操作:設置了GraphQL用戶端的配置和查詢定義,並定義了用於創建令牌的方法。

使用认证令牌来获取电费信息。

好吧,现在我认为已经创建了认证令牌,所以我将根据该令牌创建用于获取电费的HTTP客户端。

require "graphql/client"
require "graphql/client/http"

module OctopusClient    
  HTTP = GraphQL::Client::HTTP.new("https://api.oejp-kraken.energy/v1/graphql/") do
    def headers(context)
      { "Authorization" => "#{OctopusAuthenticationToken.new.generate_token}" }
    end
  end

  Schema = GraphQL::Client.load_schema(HTTP)
  Client = GraphQL::Client.new(schema: Schema, execute: HTTP)
end

在上述中,通过阅读lib/octopus_authentication_token.rb中创建的OctopusAuthenticationToken类的实例方法,获取令牌并设置到头部,在此基础上创建Client。

当你访问octopus_energy_bill/index时,会进行API调用的实现。

class OctopusEnergyBillController < ApplicationController

  GetBillQUERY = OctopusClient::Client.parse <<~'GRAPHQL'
	query(
		$accountNumber: String!
		$fromDatetime: DateTime
		$toDatetime: DateTime
	) {
		account(accountNumber: $accountNumber) {
			properties {
				electricitySupplyPoints {
					agreements {
						validFrom
					}
					halfHourlyReadings(
						fromDatetime: $fromDatetime
						toDatetime: $toDatetime
					) {
						startAt
            endAt
						value
						costEstimate
						consumptionStep
						consumptionRateBand
					}
				}
			}
		}
	}
  GRAPHQL

  def index 
    result = OctopusClient::Client.query(GetBillQUERY, variables: {
      accountNumber: ENV['OCTOPUS_ACCOUNT_NUMBER'],
      fromDatetime: Date.yesterday.beginning_of_day.iso8601,
      toDatetime: Date.yesterday.end_of_day.iso8601
      })
    properties = result.original_hash.dig("data", "account", "properties")
    electricity_supply_points = properties.first["electricitySupplyPoints"]
    half_hourly_readings = electricity_supply_points.first["halfHourlyReadings"]
    @kwh = half_hourly_readings.pluck("value").map(&:to_f).sum
    @cost = half_hourly_readings.pluck("costEstimate").map(&:to_f).sum
    puts "#{Date.yesterday.strftime('%Y年%m月%d日')}#{@kwh.round(2)}kWh消費して#{@cost}円かかったよ" 
  end
end

+  resources :octopus_energy_bill, only: %i[index]

另外,针对本次实施,我创建了一个问题(issue)来进行实施,如果有需要,可以作为参考。

 

利用 Line Messaging API 实现将获取的电费信息发送给用户的功能实例化。

我将像上一章一样安装下面的gem。

gem 'line-bot-api'

 

我們將創建一個Messaging API通道。

 

由於上述文章已經詳細解釋過,所以在本文中將省略不再提及。

スクリーンショット 2023-10-17 1.10.21.png

在上述的形式下,我们制作了一个关于Octopus Energy的非官方机器人。

另外,将创建的渠道密钥命名为LINE_CHANNEL_SECRET,将渠道访问令牌命名为LINE_CHANNEL_TOKEN,并在.env文件中进行定义。

现在,我们将使用频道密钥和频道访问令牌来创建客户端。

class LineBotClient
  def client 
    Line::Bot::Client.new { |config|
      config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
      config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
    }
  end
end

通过这个描述,您可以创建LineBotClient.new.client和Line::Bot::Client的实例。

好吧,让我们使用上面的内容来发送一条LINE消息吧!

class OctopusEnergyBillController < ApplicationController

	GetBillQUERY = OctopusClient::Client.parse <<~'GRAPHQL'
		query(
			$accountNumber: String!
			$fromDatetime: DateTime
			$toDatetime: DateTime
		) {
			account(accountNumber: $accountNumber) {
				properties {
					electricitySupplyPoints {
						agreements {
							validFrom
						}
						halfHourlyReadings(
							fromDatetime: $fromDatetime
							toDatetime: $toDatetime
						) {
							startAt
							endAt
							value
							costEstimate
							consumptionStep
							consumptionRateBand
						}
					}
				}
			}
		}
  GRAPHQL

  def index 
    result = OctopusClient::Client.query(GetBillQUERY, variables: {
      accountNumber: ENV['OCTOPUS_ACCOUNT_NUMBER'],
      fromDatetime: Date.yesterday.beginning_of_day.iso8601,
      toDatetime: Date.yesterday.end_of_day.iso8601
      })

    properties = result.original_hash.dig("data", "account", "properties")
    electricity_supply_points = properties.first["electricitySupplyPoints"]
    half_hourly_readings = electricity_supply_points.first["halfHourlyReadings"]
    @kwh = half_hourly_readings.pluck("value").map(&:to_f).sum
    @cost = half_hourly_readings.pluck("costEstimate").map(&:to_f).sum
-   puts "#{Date.yesterday.strftime('%Y年%m月%d日')}#{@kwh.round(2)}kWh消費して#{@cost}円かかったよ"
+   text = "#{Date.yesterday.strftime('%Y年%m月%d日')}#{@kwh.round(2)}kWh消費して#{@cost}円かかったよ" 

+	message = {
+     type: 'text',
+     text: text
+    }
+    LineBotClient.new.client.broadcast(message)
  end
end

当您访问/octopus_energy_bill端点后,您可以通过LINE发送以下内容。

IMG_9781.png

本次目标已经完成了!

最终

这次我们使用GraphQL和Rails(API模式)开发了一个电费Line机器人,您觉得如何?

下次我们打算进行部署和定期执行?

非常感谢您阅读至最后!

后续报道

 

文献引用

 

bannerAds