次に、BOTとのやり取りを行うための設定として以下の画像と同じになるように
設定を変更してください。
FROM ubuntu:22.04
# タイムゾーンの設定(インタラクティブなプロンプトを避けるため)
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Tokyo
# 必要なパッケージのインストール
RUN apt-get update && apt-get install -y \
tzdata \
python3 \
python3-pip \
python3-venv \
git \
iputils-ping \
vim \
&& ln -fs /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
&& dpkg-reconfigure -f noninteractive tzdata \
&& echo "Asia/Tokyo" > /etc/timezone \
&& rm -rf /var/lib/apt/lists/*
# 作業ディレクトリの作成
WORKDIR /app
# Pythonの依存関係ファイル
COPY requirements.txt .
# 依存関係のインストール
RUN pip3 install --no-cache-dir -r requirements.txt
# コンテナを終了させないために sleep infinity を実行
CMD ["sleep", "infinity"]
version: '3'
services:
discord-bot:
build: .
volumes:
- .:/app
restart: unless-stopped
env_file:
- .env
OCTOPUS_EMAIL=<オクトパスエナジーに登録しているメアド>
OCTOPUS_PW=<オクトパスエナジーのパスワード>
ACCOUNT_NUMBER=<オクトパスエナジーのお客さま番号>
DISCORD_TOKEN=<さっきコピーしたToken>
DISCORD_CHANNEL_ID=<DiscordサーバのID>
discord.py>=2.0.0
python-dotenv>=0.19.0
requests>=2.32.3
docker-compose up --build
docker exec -it <Container name> bash
import requests
import os
from dotenv import load_dotenv
# .env ファイルから環境変数を読み込む
load_dotenv()
def get_auth_token():
# GraphQL エンドポイント
GRAPHQL_URL = "https://api.oejp-kraken.energy/v1/graphql/"
# GraphQL Mutation クエリ
graphql_query = """
mutation login($input: ObtainJSONWebTokenInput!) {
obtainKrakenToken(input: $input) {
token
}
}
"""
# 送信するデータ
variables = {
"input": {
"email": os.getenv('OCTOPUS_EMAIL'),
"password": os.getenv('OCTOPUS_PW')
}
}
# HTTP ヘッダー
headers = {
"Content-Type": "application/json"
}
try:
response = requests.post(
GRAPHQL_URL,
json={"query": graphql_query, "variables": variables},
headers=headers
)
response_data = response.json()
if "errors" in response_data:
print("認証エラー:", response_data["errors"])
return None
token = response_data["data"]["obtainKrakenToken"]["token"]
return token
except Exception as e:
print("エラーが発生しました:", str(e))
return None
# 実行
if __name__ == "__main__":
token = get_auth_token()
print("取得したトークン:", token)
# bot.py
import requests
import subprocess
import os
from datetime import datetime, timedelta
import json
from dotenv import load_dotenv
import auth_token_retriever
# .env ファイルから環境変数を読み込む
load_dotenv()
# Octopus Energy API の設定
OCTOPUS_TOKEN = auth_token_retriever.get_auth_token()
ACCOUNT_NUMBER = os.getenv('ACCOUNT_NUMBER')
# GraphQL エンドポイント
GRAPHQL_URL = "https://api.oejp-kraken.energy/v1/graphql/"
def get_electricity_consumption():
# 現在の日時を取得
now = datetime.utcnow()
# 前日の日付を計算
previous_day = now - timedelta(days=1)
# "YYYY-MM-DDTHH:MM:SS+00:00Z" 形式に変換
str_date = previous_day.strftime("%Y-%m-%d")
start_date = previous_day.strftime("%Y-%m-%dT00:00:00+00:00Z")
end_date = now.strftime("%Y-%m-%dT00:00:00+00:00Z")
"""指定期間の電気使用量を取得する"""
# GraphQL クエリ
QUERY = """
query halfHourlyReadings($accountNumber: String!, $fromDatetime: DateTime, $toDatetime: DateTime) {
account(accountNumber: $accountNumber) {
properties {
electricitySupplyPoints {
status
agreements {
validFrom
}
halfHourlyReadings(fromDatetime: $fromDatetime, toDatetime: $toDatetime) {
startAt
value
costEstimate
consumptionStep
consumptionRateBand
}
}
}
}
}
"""
# リクエスト用の変数
VARIABLES = {
"accountNumber": ACCOUNT_NUMBER,
"fromDatetime": start_date,
"toDatetime": end_date
}
# リクエストヘッダー(API トークンを含む)
HEADERS = {
"Content-Type": "application/json",
"Authorization": OCTOPUS_TOKEN
}
try:
response = requests.post(GRAPHQL_URL, json={"query": QUERY, "variables": VARIABLES}, headers=HEADERS)
# ステータスコードをチェック
if response.status_code != 200:
print(f"❌ エラー: ステータスコード {response.status_code}")
print(response.text)
return None
# JSON レスポンスを解析
data = response.json()
# GraphQL のエラー処理
if "errors" in data:
print("❌ GraphQL エラー:", json.dumps(data["errors"], indent=2, ensure_ascii=False))
return None
# JSON からデータを抽出
properties = data["data"]["account"]["properties"]
electricity_supply_points = properties[0]["electricitySupplyPoints"]
half_hourly_readings = electricity_supply_points[0]["halfHourlyReadings"]
# 消費電力とコストを合計
kwh = sum(float(reading["value"]) for reading in half_hourly_readings)
cost = sum(float(reading["costEstimate"]) for reading in half_hourly_readings)
# 結果を整形
text = f"{str_date}は{kwh:.2f}kWh消費して{cost:.0f}円でした。"
return text
except requests.exceptions.RequestException as e:
print(f"❌ リクエストエラー: {e}")
return None
if __name__ == "__main__":
result = get_electricity_consumption()
if result:
print("✅ 取得成功!:")
print(result)
else:
print("⚠ データを取得できませんでした。")
# bot.py
import requests
import subprocess
import os
import datetime
import discord
from discord.ext import commands, tasks
from dotenv import load_dotenv
# .env ファイルから環境変数を読み込む
load_dotenv()
# Discord botのトークンを取得
DISCORD_TOKEN = os.getenv('DISCORD_TOKEN')
DISCORD_CHANNEL_ID = int(os.getenv('DISCORD_CHANNEL_ID'))
# Intentを設定
intents = discord.Intents.default()
intents.message_content = True # メッセージ内容へのアクセスを有効化
# ボットの初期化
intents = discord.Intents.default()
intents.message_content = True
bot = commands.Bot(command_prefix="!", intents=intents)
# login event
@bot.event
async def on_ready():
print(f'{bot.user.name} としてログインしました!')
print('------------------------------------')
@bot.event
async def on_message(message):
print(f"メッセージ受信: {message.content}")
await bot.process_commands(message)
# test
@bot.command()
async def run(ctx, script_name: str = None):
if script_name is None:
await ctx.send("⚠ エラー: スクリプト名を指定してください。\n使用例: `!run sample`")
return
script_path = os.path.join(os.getcwd(), script_name )
if not os.path.exists(script_path):
await ctx.send(f"エラー: `{script_name}` が見つかりません。")
return
try:
# スクリプトを実行し、出力を取得
result = subprocess.run(
["python3", script_path],
capture_output=True, text=True, timeout=10
)
output = result.stdout or "スクリプトの実行が完了しました。"
await ctx.send(f"✅ `{script_name}` の実行結果:\n```\n{output}\n```")
except Exception as e:
await ctx.send(f"❌ スクリプトの実行中にエラーが発生しました:\n```\n{e}\n```")
# Botを実行
if __name__ == "__main__":
bot.run(DISCORD_TOKEN)
python3 main.py
!run Electricity_bill_inquiry.py