Tuya API (Smart Life)とスマートプラグでバッテリーにやさしい充電をする仕掛け

スポンサーリンク

はじめに

本記事は旧Tuya APIの内容であり、2021年12月現在、実施できない状態になっています。

Tuya APIが刷新され、下記記事で新しいTuya APIの使い方を紹介していますのでご覧ください。

ノートパソコンのバッテリは消耗品で、使っているとだんだん弱っていきます。

バッテリーがすぐ切れると困るので、できるだけ長持ちさせたいですよね。

ノートパソコンのバッテリを長持ちさせる方法は様々なサイトで紹介されています。

この記事では、MacのApple Scriptを使って、自動的にバッテリーにやさしい充電をする方法を紹介します。

(2021年5月8日追記)
本記事のまとめに7ヶ月間試した結果を説明する動画のリンクを追加しました。

過去の記事で、IFTTTを利用してWebhookからSmart Lifeのスマートプラグを操作する方法を紹介したのですが、2020年5月26日からSmart LifeがIFTTTに対応しなくなったため、Tuya APIを使用する方法に切り替えました。

Liイオンバッテリについて

ノートパソコンのバッテリとして現在主流のLiイオンバッテリを長持ちさせるには、

  • 電源つなぎっ放しはダメ
  • 20%〜80%の間で使う
  • 充電度合いが少ない状態で使う
  • 充電度合いの変動幅は小さく

バッテリーの専門家ではないため、間違った情報があるかもしれません。
また、ニッケル水素バッテリーなど、他のバッテリー種には当てはまりません。

以上を考慮して、50%〜55%の充電状態をキープするようにしました。

構成一覧

構成要素バージョン
macOSCatalina 10.15.7
Node.jsv12.18.0
npm8.2.0
スマートプラグ中国製Smart Life対応
型番: XS-A16

スマートプラグの設定

スマートプラグは、家庭のコンセントにつないでインターネット経由で電源のON/OFFを切り替えられる機器です。

Smart Plug

Amazon EchoやGoogle Homeなどのスマートスピーカから制御できるもの、IFTTT経由で制御できるものなどがあります。

以下のようなSmart Homeアプリ対応のスマートプラグであれば、本記事と同じことができます。

スマートプラグ WiFi スマートコンセント Echo Alexa Google ホーム対応

スマートプラグの説明書に載っている2次元バーコードから「Smart Life」のアプリをインストールし、このページなどを参考に、メールアドレス登録→家族(自分)を作成→デバイス追加の順に設定します。

デバイスの追加はアプリの右上にある+マークをタップし、家電製品(Electrical Engeneerings)→コンセント(Socket)へと進み、Wifiのパスワードを登録します。

クラウド(Tuya IoT)の設定

クラウド側の設定をします。(参考

まず、https://iot.tuya.com からアカウント作成してログインし、ページ上部のCloud Developmentを押すと以下のページが表示されます。

Tuya login

プロジェクトの作成

Createボタンを押すと下図のように表示されるので、記入していきます。

内容は何でも良いようです。
私は次のようにしました。

Project Name: Toggle Plug
Description: Operate the smart plug remotely.
industry: Smart Home

下図のようにAccess IDとAccess Secretが表示されます。

これらは後で使うので、Copyを押してコピーし、テキストエディタに貼り付けるなどしてメモを取っておきます。

Tuya project

アプリの作成

次にページ上部のApp Service→左メニューApp SDKを押して下の画面に移行します。

Tuya App SDK

画面中央のObtain SDKボタンを押すと下のポップアップが出るので、Wi-Fi device solutionを選択して
Nextを押します。

以下のポップアップが出るのでアプリ情報を記入してConfirmを押します。

私は以下のようにしました。

App Name: Plug
iOS Bundle ID: com.smartlife.plug
Android Package Name: com.smartlife.plug
Channel ID: smartlifeplug

iOSやAndroidは使用しませんが、記入は必須のようです。

ここで入力したChannel IDも後で使うのでメモしておきます。

プロジェクトにアプリをリンク

上部メニューのCloud Development→左メニューLinked Devices→Linked devices by Apps
で以下のように表示されるので、Add Appsを押してアプリを追加します。

Tuya link devices

作成したアプリにチェックを入れ、OKを押します。

Tuya Choose App

Tuya API環境構築

ここでの作業を行う環境して、以下である必要があるとのことです。

  • 2.4GHz 帯のWi-Fiがあること。
  • PCが、スマートプラグと同じWi-Fiにつながっていること。
  • そのネットワークでクライアント間通信ができること。
  • PCに他のネットワークインタフェイス(有線LANなど)がないこと。
    複数のインターフェイスがあると、優先順位によってはパケットが正しく送られない場合あり。

CLIのインストール

npmがインストールしていない方はこちらからNode.jsの推奨版をインストールしてから以下を実行します。

$ sudo npm i -g @tuyapi/cli

ペアリング

スマートプラグを電源に接続し、ボタンを長押ししてペアリングモードにします。

ペアリングモードには2種類あり、LED点滅が速い方にします。

私の場合、電源を入れて単に長押しするとこのモードになりました。

Macのターミナルから次のコマンドを実行します。

$ tuya-cli link --api-key "Access ID" --api-secret "Access Secret" --schema "Channel ID" --ssid "ネットワークのSSID" --password "ネットワークのパスワード" --region us

以下のように表示されれば成功です。

✔ Device(s) registered!
[
  {
    id: 'xxxxxxxxxxxxxxxxxxxx',
    ip: 'xxx.xxx.xxx.xxx',
    localKey: 'xxxxxxxxxxxxxxxx',
    name: '智能插座'
  }
]

表示されたidとlocalKeyはAPI呼び出しの際に使うのでメモしておきます。

APIのダウンロード

APIをダウンロードします。

$ npm i -S codetheweb/tuyapi

codetheweb/tuyapiのreadmeには非同期版と同期版の例があり、非同期版が推奨となっていますが、非同期版を使うと時々”Unhandled promise error”が発生し、その後APIにアクセスできなくなる問題が発生したので、同期版を採用しました。

同期版を使った場合でも、時々”Socket error”が発生するため、3回はトライするようにしました。

これで、大抵2回目には接続に成功するようになりました。

以下をplug_sync.jsなどのファイル名で保存します。

id, keyにはペアリングの際に表示されたidとlocalKeyを入れます。

const TuyAPI = require('tuyapi');

const device = new TuyAPI({
  id: 'xxxxxxxxxxxxxxxxxxxx',
  key: 'xxxxxxxxxxxxxxxx'});

let powStat = process.argv[2] == "on" ? true : false;

(async () => {
  await device.find();
  await device.connect();

  let status = await device.get();
  console.log('Set:', status, '=>', powStat);
  await device.set({set: powStat});

  device.disconnect();
})();

引数をonにすると電源ON、それ以外(offなど)は電源OFFにするプログラムになっています。

ここでAPIの動作確認を行います。
以下のコマンドでON/OFFできるか試します。

$ node plug_sync.js on
Set: false => true
$ node plug_sync.js off
Set: true => false

これで正常にON/OFFできればよいです。

次にApple Scriptで充電の度合いに応じてこのコマンドを実行するようにします。

次の章へ進んでください。

以下、当初使っていた非同期版のスクリプトを参考までに掲載します。

const TuyAPI = require('tuyapi');

const device = new TuyAPI({
  id: 'xxxxxxxxxxxxxxxxxxxx',
  key: 'xxxxxxxxxxxxxxxx'});

let powStat = process.argv[2] == "on" ? true : false;

// Find device on network
device.find().then(() => {
  // Connect to device
  device.connect();
});

// Add event listeners
device.on('connected', () => {
  console.log('Connected to device!');
});

device.on('disconnected', () => {
  console.log('Disconnected from device.');
});

device.on('error', error => {
  console.log('Error!', error);
});

device.on('data', data => {
  //console.log('Data from device:', data);

  // Plug on/off
  if (data.dps['1'] != powStat) {
    console.log('Set:', data.dps['1'], '=>', powStat);
    device.set({set: powStat});
  }
});

// Disconnect after 3 seconds
setTimeout(() => { device.disconnect(); }, 3000);

Apple Scriptの作成

画面右上(メニューバー上)の虫眼鏡マーク(Sporlight Search)からScript Editor.appを検索してダブルクリックで起動します。

以下のコードをScript Editorに貼り付けます。

plug_async.jsのファイルパスはお使いの環境に合わせて変えてください。

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

global MIN, MAX, AWAKE

set MIN to 50
set MAX to 55

set AWAKE to true

set aCenter to current application's NSWorkspace's sharedWorkspace()'s notificationCenter()
aCenter's addObserver:me selector:"notifSleep:" |name|:"NSWorkspaceWillSleepNotification" object:(missing value)
aCenter's addObserver:me selector:"notifWaked:" |name|:"NSWorkspaceDidWakeNotification" object:(missing value)

on exeAPI(message)
    -- say "The AWAKE value is " & AWAKE
    if AWAKE then
        try
            -- say "Start API"
            do shell script "/usr/local/bin/node /Users/user/plug_sync.js " & message & "> /Users/user/plug_sync.log 2>&1"
            -- say "Normal end"
        on error
            -- say "Error occurred"
            -- display dialog "Error occurred"
            return 1
        end try
    end if
    return 0
end exeAPI

on idle
    set per to (do shell script "pmset -g batt | grep % | sed 's/[%;]/ /' | awk '{print $3}'") as number
    set ret to 1
    set cnt to 0
    repeat while cnt < 3 and ret /= 0
        -- say "The count is " & cnt
        if per ≤ MIN then
            set ret to my exeAPI("on")
        else if MAX ≤ per then
            set ret to my exeAPI("off")
        end if
        set cnt to cnt + 1
    end repeat
    return 60
end idle

on quit
    exeAPI("off")
    continue quit
end quit

on notifSleep:aNotif
    exeAPI("off")
    -- display notification "System will sleep"
    -- say "System will sleep"
    set AWAKE to false
end notifSleep:

on notifWaked:aNotif
    -- display notification "System did wake"
    -- say "System did wake"
    set AWAKE to true
end notifWaked:

スクリプトの解説

MIN, MAXの値を変えればお好みの充電範囲にできます。

/usr/local/bin, /Users/userなどのパスはお使いの環境に合わせて変更してください。

on idle, return 60 として60秒毎にバッテリーの充電度合いを確認し、MIN以下なら充電開始、MAX以上なら充電停止しています。

nodeコマンドは3回トライしています。

当初は、on idle部のみで充電を制御しようとしていました。

しかし、電源ON状態でシャットダウンするとそのまま充電され続けてしまうため、on quitでシャットダウン時のApplication停止を検知して充電を停止するようにしました。

その後、電源ON時にスリープモードに入った場合も充電され続けてしまうことに気づきました。

notificationCenterの記述とon notifSleep:aNotifを追加し、スリープモードに入る通知を取得して充電を止めるようにしました。

ところが、スリープモードでもスクリプトは動作しているようでMIN以下になるとon idleの機能が働いて電源がONになります。

そのまま少し経つとディープスリープモードに移行してスクリプトが停止して充電し続けます。

これを避けるために、スリープと復帰の両方の通知を検知して、現在スリープモード中かどうかを確認し、スリープモード中は電源ON/OFFを変更しないようにしました。

これで、スリープ状態に入るときに電源をOFFにし、スリープから復帰するまで電源OFFをキープするようにしました。

スクリプトの保存

Script Editor上部のツルハシの絵が付いているボタンを押すとキーワードに色が付き、見やすくなります。

File→Saveから保存します。

File FormatをApplicationにし、オプション:ハンドラの実行後に終了しない(Stay open after run handler)にチェックを入れます。

私はPowerManagerAPI.appという名前で保存しました。

ScriptEditor save

続いて、このApple Script ApplicationをMac起動時に立ち上がるように設定します。

Appleマークからシステム環境設定(System Preferences)
→ユーザーとグループ(Users & Groups)
→ログイン項目(Login Items)
から+マークを押すと選択画面が出るので、作成したPowerManagerAPI.appを選択します。

User Login Items

Macを再起動して、充電度合い50〜55%をキープするように自動的にスマートプラグがON/OFFされ、
シャットダウン時やスリープモード移行時にスマートプラグがOFFになれば成功です。

追加情報

本Apple ScriptをDockに表示させたくない場合は、以下を実行するとよいです。
(以下はPowerManagerAPI.appの保存場所がDocuments/scriptsの場合の例)

$ cd Documents/scripts
$ plutil -insert 'LSUIElement' -bool true PowerManagerAPI.app/Contents/Info.plist

インターネットにつながらない場所では、1分おきにコマンドに失敗したというポップアップが出てしまいますが、Editを押してScript Editorを立ち上げておくと出なくなります。

このページのblife.shは、バッテリーに関する情報をまとめて表示してくれるので便利です。

$ blife.sh 
[2019-06-15 00:08:05]
Your MacBook's Battery status is
Charge Remaining 2127(mAh)
State of Charge  50%
Cycle Count  21
Cycle Count Remaining 979
Full Charge Capacity 4175(mAh)
State of Health  96.8%

まとめ

Tuya APIを利用してスマートプラグをApple Scriptから操作し、バッテリーにやさしい充電をする仕掛けを作りました。

Tuya APIは同期版を採用していますが、ときどき通信に失敗するので、複数回トライするようにしてほぼ失敗を無くす工夫をしました。

Apple Scriptとしては、シャットダウン時やスリープ時などにも通知を利用して充電し続けない工夫をしました。

ご興味をお持ちの方のご参考になれば幸いです。

(2021年5月8日追記)
本記事の内容を7ヶ月間試した結果を以下の動画で説明していますので、よろしければご覧ください。
ただし、大きくは劣化していない、ということ以外断言できていないのですが・・・

お断り

充電度合いの測定には誤差があるのか、設定した充電範囲を多少越えることがあります。

別の観点として、常に充電状態にしておく方が充放電回数(Cycle Count)が進みづらいと書いているサイトもあるようなので、バッテリー劣化より充放電回数を重視する(売却時に参考されるため)場合、本サイトの内容は適さない可能性があります。

本サイトの内容に従って、何らかの損害が発生しても責任を負いかねますので、あくまで自己責任でお願いします。

参考文献

タイトルとURLをコピーしました