はじめに
PythonでAndroidアプリが作れるなら <記事:PythonでAndroidアプリを作る。> 、スマホの各種センサー情報を使ってアプリが作れないか?調べてみた。Plyerというkivy用のAPIで各種センサー情報を取得できることがわかったので記事にする。
Plyerはこちら
目次
Plyerとは
Kivyのフレームワーク上で動作するAPI。OSごとにできることに違いがあり、Androidのサポートは多い印象。この記事では動作確認の取れた〇を中心にまとめる。GPSも試してみたが、Pydroid3ではうまくいくけど、buildozerでアプリ化すると動作不安定になるため△とした。原因がわかり次第、別途記事にする。
センサー以外にも、ライトを光らせる、カメラを動作させる、画面の明るさを変更する、バイブレーションを動かす。など色々できるようだが、また別の機会で記事にしたいと思う。
API | 内容 | Android | iOS | Win | OS X | Linux |
---|---|---|---|---|---|---|
Accelerometer | 加速度センサー | 〇 | ✔ | ✔ | ✔ | |
Gravity | 重力センサー | 〇 | ✔ | |||
Gyroscope | ジャイロセンサー | 〇 | ✔ | |||
Compass | 電子コンパス | 〇 | ✔ | |||
Battery | バッテリー情報 | 〇 | ✔ | ✔ | ✔ | ✔ |
Temperature | 温度センサー | 〇 | ||||
Light | 照度センサー | 〇 | ||||
Barometer | 気圧センサー | 〇 | ✔ | |||
GPS | 位置情報 | △ | ✔ |
Plyerで各種センサー情報を取得する
各々のAPIの使い方をまとめる。enable()
して値を読むだけなので、比較的簡単にAPIを使うことができる。注意点としてはkivyフレームワーク上でしか動作しないので、plyerを単独で使うことはできない。値が取れない場合はNone
が返答される。
Accelerometer(加速度センサー)
加速度をx,y,z軸で取得する。accelerometer.acceleration
でタプル型で取得。
from plyer import accelerometer
#有効
accelerometer.enable()
#取得
x,y,z = accelerometer.acceleration
if x!=None or y!=None or z!=None:
output=f'Accelemeter\nx:{x:0.3f} m/s2\ny:{y:0.3f} m/s2\nz:{z:0.3f} m/s2\n\n'
else:
output=f'Accelemeter\nx: m/s2\ny: m/s2\nz: m/s2\n\n'
Gravity(重力センサー)
重力加速度をx,y,z軸で取得する。gravity.gravity
でタプル型で取得。
from plyer import gravity
#有効
gravity.enable()
#取得
x,y,z = gravity.gravity
if x!=None or y!=None or z!=None:
output+=f'Gravity\nx:{x:0.3f} m/s2\ny:{y:0.3f} m/s2\nz:{z:0.3f} m/s2\n\n'
else:
output=f'Gravity\nx: m/s2\ny: m/s2\nz: m/s2\n\n'
Gyroscope(ジャイロセンサー)
角速度をx,y,z軸で取得する。gyroscope.rotation
でタプル型で取得。
from plyer import gyroscope
#有効
gyroscope.enable()
#取得
x,y,z = gyroscope.rotation
if x!=None or y!=None or z!=None:
output+=f'Gyroscope\nx:{x:0.3f} rad/s\ny:{y:0.3f} rad/s\nz:{z:0.3f} rad/s\n\n'
else:
output=f'Gyroscope\nx: rad/s\ny: rad/s\nz: rad/s\n'
Compass(電子コンパス)
磁力をx,y,z軸で取得する。compass.field
でタプル型で取得。
from plyer import compass
#有効
compass.enable()
#取得
x,y,z = compass.field
if x!=None or y!=None or z!=None:
output+=f'Compass\nx:{x:0.3f} uT\ny:{y:0.3f} uT\nz:{z:0.3f} uT\n\n'
else:
output=f'Compass\nx: uT\ny: uT\nz: uT\n\n'
Battery(バッテリー情報)
バッテリーの残量と、現在充電中かどうかを取得する。battery.status
で辞書型で取得。isCharging
が充電中かどうか。percentage
がバッテリー残量。
from plyer import battery
#batteryはenable()不要。
#取得
output+=f'Battery\nCharging:{battery.status["isCharging"]}\n{battery.status["percentage"]}%\n\n'
Temperature(温度センサー)
温度を取得する。temperature.temperature
で取得。私のスマホは、常にNoneが返答されたので、スマホ自体が対応していないのだと思う。
from plyer import temperature
#有効
temperature.enable()
#取得
output+=f'Temperature\n{temperature.temperature}\n\n'
Light(照度センサー)
明るさを取得する。light.illumination
で取得。
from plyer import light
#有効
light.enable()
#取得
output+=f'illumination:\n{light.illumination:0.3f} lux\n\n'
Barometer(気圧センサー)
気圧を取得する。barometer.pressure
で取得。
from plyer import barometer
#有効
barometer.enable()
#取得
output+=f'Barometer\n{barometer.pressure:0.2f} hPa\n\n'
PlyerのAndroidアプリ例
KivyのTextInputに1/30秒(スマホが30fpsなので)ごとに値を更新する例を作ってみた。buildozerでアプリ化するためのbuildozer.specも併せて記載する。buildozer.specは、初期値から変更した行だけ抜き出した。アプリの作り方は <記事:PythonでAndroidアプリを作る。> を参照。
main.py/buildozer.specファイルはこちら。
from kivy.app import App
from kivy.uix.textinput import TextInput
from kivy.clock import Clock
#Sensor
from plyer import accelerometer
from plyer import gravity
from plyer import gyroscope
from plyer import compass
from plyer import battery
from plyer import temperature
from plyer import light
from plyer import barometer
#for compass
import math
import numpy as np
class SensorApp(App):
#---------------------------
# グローバル変数
#---------------------------
cnt=0
toggle='off'
#---------------------------
# 初期化
#---------------------------
def build(self):
#TextInput
self.text = TextInput(text='')
#enable each plyer lib
accelerometer.enable()
gravity.enable()
gyroscope.enable()
compass.enable()
temperature.enable()
light.enable()
barometer.enable()
# Update every 1/30sec
Clock.schedule_interval(self.update_plyer, 1/30)
return self.text
#---------------------------
# 1/30 sec 毎に更新 InputTextへ出力
#---------------------------
def update_plyer(self, dt):
self.cnt+=1
#accelerometer
x,y,z = accelerometer.acceleration
if x!=None or y!=None or z!=None:
output=f'Accelemeter\nx:{x:0.3f} m/s2\ny:{y:0.3f} m/s2\nz:{z:0.3f} m/s2\n\n'
else:
output=f'Accelemeter\nx: m/s2\ny: m/s2\nz: m/s2\n\n'
#gravity
x,y,z = gravity.gravity
if x!=None or y!=None or z!=None:
output+=f'Gravity\nx:{x:0.3f} m/s2\ny:{y:0.3f} m/s2\nz:{z:0.3f} m/s2\n\n'
else:
output=f'Gravity\nx: m/s2\ny: m/s2\nz: m/s2\n\n'
#gyroscope
x,y,z = gyroscope.rotation
if x!=None or y!=None or z!=None:
output+=f'Gyroscope\nx:{x:0.3f} rad/s\ny:{y:0.3f} rad/s\nz:{z:0.3f} rad/s\n\n'
else:
output=f'Gyroscope\nx: rad/s\ny: rad/s\nz: rad/s\n'
#compass
x,y,z = compass.field
if x!=None or y!=None or z!=None:
output+=f'Compass\nx:{x:0.3f} uT\ny:{y:0.3f} uT\nz:{z:0.3f} uT\ndegree:{self.orientation(x,y,z):0.3f}\n\n'
else:
output=f'Compass\nx: uT\ny: uT\nz: uT\n\n'
#battery
output+=f'Battery\nCharging:{battery.status["isCharging"]}\n{battery.status["percentage"]}%\n\n'
#temperature
output+=f'Temperature\n{temperature.temperature}\n\n'
#light
if light.illumination!=None:
output+=f'illumination:\n{light.illumination:0.3f} lux\n\n'
#barometer
if barometer.pressure!=None:
output+=f'Barometer\n{barometer.pressure:0.2f} hPa\n\n'
self.text.text = output
#---------------------------
# 方位計算
#---------------------------
def orientation(self,x,y,z):
# ベクトル変換 (x,y逆転しないと90度ずれたため。)
mag_vector = np.array([y, x, z])
# 地磁気ベクトルを計算
mag_strength = np.linalg.norm(mag_vector)
mag_unit_vector = mag_vector / mag_strength
# ラジアン変換
radian = math.atan2(mag_unit_vector[1], mag_unit_vector[0])
# 度変換
degree = math.degrees(radian)
# 方位0から360度へ調整
degree = (degree + 360) % 360
return degree
if __name__ == '__main__':
SensorApp().run()
[app]
# (str) Title of your application
title = Plyer_test
# (str) Package name
package.name = plyer_test
# (list) Application requirements
requirements = python3, kivy, plyer, android, numpy
# (list) Permissions
android.permissions = INTERNET,ACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATION
以上