やりたいこと
ArduinoからGoogle Cloud Messaging(以下「GCM」)を叩いて、Android端末にメッセージを送ってみたい。
要件的なもの
・GCMメッセージを送るAndroid端末(以下「端末」)は2台。(device1, device2とする。1台しかない場合はdevice1の値をdevice2に使いまわす。)
・ブレッドボート上に置いたDIPスイッチでメッセージ送信先の端末を決める。
・ブレッドボート上に置いたタクトスイッチを押すと、タクトスイッチごとに設定したメッセージが端末に送信される。
・REGISTRATION_ID(GCMが端末を識別するために必要な文字列)は手動で取得し、inoファイル上にコピペする。
・ArduinoはデフォルトではSSL通信をサポートしていないので、GCMのPOST先はhttpsではなくてhttpを使用する。(httpでも送れちゃったのでよしとする)
必要なもの
- Arduino Uno R3
(ここで実際に使用しているのはArduino Uno互換の DFRduino UNO R3) - Arduino Ethernet Shield
(ここで実際に使用しているのはDFRduino Ethernet Shield V2.1) - ブレッドボード
- タクトスイッチ x3
- DIPロータリースイッチ(0-F 正論理)
- 10kΩ抵抗 x4
- ジャンパコード x10くらい
- ジャンパワイヤ x10くらい
- Android 2.3以上の端末 x2
- Arduino用のプログラム(GoogleCloudMessaging.ino) ソースは後述
- Android用のアプリ(GcmArduino) ソースは後述
やり方
1. REGISTRATION_IDを取得する
GcmArduinoアプリからREGISTRATION_IDを取得し、GoogleCloudMessaging.inoにコピペする。
REGISTRATION_IDは「Implementing GCM Client on Android」にあるtokenのこと。
2. DIPロータリースイッチで送信先を決める
ブレッドボード上のDIPロータリースイッチで送信先の端末を決める。
DIPロータリースイッチの値が、
0ならdevice1とdevice2に送信する。
1ならdevice1に送信する。
2ならdevice2に送信する。
3. タクトスイッチでメッセージを送信する
タクトスイッチごとに以下のメッセージを送信する。
黄色:タイトルが「Yellow」・本文が「YELLOW!」・着信音が端末のTYPE_RINGTONE
青色:タイトルが「Blue」・本文が「BLUE!」・着信音が端末のTYPE_NOTIFICATION
緑色:タイトルが「Green」・本文が「GREEN!」・着信音が端末のTYPE_ALARM
4. GCMサーバにメッセージをPOSTする
ArduinoはデフォルトでSSL通信をサポートしていないので、POST先のURLは「https」ではなくて「http」を使用する。
(なのでREGISTRATION_IDはダダ漏れになるという前提で使うこと)
5. GCM GCM GCM…
Google様にゴニョゴニョして頂く。
6. 端末でメッセージを受け取る
押したタクトスイッチごとに着信音とかが変わってメッセージが受信されていれば成功。
Android側(GcmArduinoアプリ)
・IDEはAndroid Studio
・大元のソースはCode Samplesにあるサンプルコードなので詳細はそっち参照で。
アプリを起動してしばらくすると、logcatに「REGISTRATION_ID」が表示されるので、これをGoogleCloudMessaging.ino(後述)の「REGISTRATION_IDS[]」にコピペすること。(端末2台分)
構成
・アプリが起動すると、MyGcmRegistrationIntentServiceがGCMサーバにREGISTRATION_IDを登録してくれる。
・MyGcmListenerServiceはGCMからメッセージが来るのをじっと待つ。(Arduinoからメッセージが送られると通知する)
・MyInstanceIdListenerServiceは「REGISTRATION_ID」(GCMが端末を識別するために必要な文字列)が変更された場合に、再取得処理を行う。
ソースコード
ここに記載が無いものはデフォルトのまま。
AndroidManifest.xml
「GcmReceiver」は必要そうなので入れておく。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="jp.example.android.gcmarduino" > <!-- https://developers.google.com/cloud-messaging/android/client --> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /> <permission android:name="com.example.gcm.permission.C2D_MESSAGE" android:protectionLevel="signature" /> <uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <!-- receiving GCM messages and popup notification. onMessageReceived() --> <service android:name=".gcm.MyGcmListenerService" android:exported="false" > <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE" /> </intent-filter> </service> <!-- For onTokenRefresh https://developers.google.com/instance-id/guides/android-implementation The Instance ID service initiates callbacks periodically (for example, every 6 months), requesting that your app refreshes its tokens. --> <service android:name=".gcm.MyInstanceIdListenerService" android:exported="false"> <intent-filter> <action android:name="com.google.android.gms.iid.InstanceID"/> </intent-filter> </service> <!-- For GCM registration In order to receive GCM messages, declare GcmReceiver and an implementation of GcmListenerService in the app manifest. @see https://developers.google.com/android/reference/com/google/android/gms/gcm/GoogleCloudMessaging @see https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmReceiver --> <receiver android:name="com.google.android.gms.gcm.GcmReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND" > <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE" /> <category android:name="jp.example.android.gcmarduino" /> </intent-filter> </receiver> <service android:name=".gcm.MyGcmRegistrationIntentService" android:exported="false"> </service> <!-- Main Activity --> <activity android:name="jp.example.android.gcmarduino.activity.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> |
activity/MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
package jp.example.android.gcmarduino.activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.support.v4.content.LocalBroadcastManager; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.widget.EditText; import android.widget.TextView; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import jp.example.android.gcmarduino.R; import jp.example.android.gcmarduino.config.Const; import jp.example.android.gcmarduino.lib.Util; import jp.example.android.gcmarduino.gcm.MyGcmRegistrationIntentService; /** * MainActivity */ public class MainActivity extends AppCompatActivity { /** * BroadcastReceiver for GCM registration */ private BroadcastReceiver mBroadcastReceiverGcmRegistration; /** * REGISTRATIOM_ID */ private String registrationId; private Context context; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.i(Const.TAG, "onCreate()"); context = getApplicationContext(); mBroadcastReceiverGcmRegistration = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.i(Const.TAG, "mBroadcastReceiverGcmRegistration onReceive()"); boolean isGcmRegistrationCompleted = intent.getBooleanExtra(Const.EXTRA_GCM_REGISTERED, false); EditText textRegistrationId = ((EditText) findViewById(R.id.textRegistrationId)); if (isGcmRegistrationCompleted) { //REGISTRATION_ID registrationId = intent.getStringExtra(Const.EXTRA_GCM_REGISTRATION_ID); Util.toast(context, "GCM Registration Success!"); Log.w(Const.TAG, "copy&paste REGISTRATION_ID to Arduion ino file at"); Log.w(Const.TAG, "PROGMEM char* const REGISTRATION_IDS[] = {}"); Log.w(Const.TAG, "REGISTRATION_ID: "+registrationId); textRegistrationId.setText(registrationId); } else { Util.toast(context, "GCM Registration FAILED..."); textRegistrationId.setText(""); } } }; //check GooglePlayService if (hasPlayServices()) { startService(new Intent(this, MyGcmRegistrationIntentService.class)); } } @Override protected void onResume() { super.onResume(); Log.i(Const.TAG, "onResume()"); //receiver for GCM registration LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiverGcmRegistration, new IntentFilter(Const.INTENT_GCM_REGISTRATION)); } @Override protected void onPause() { LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiverGcmRegistration); super.onPause(); } @Override protected void onStart() { super.onStart(); Log.i(Const.TAG, "onStart()"); //show notifications from GCM Communication Server Intent intent = getIntent(); String gcmTitle = intent.getStringExtra(Const.EXTRA_GCM_TITLE); String gcmMessage = intent.getStringExtra(Const.EXTRA_GCM_MESSAGE); if (gcmTitle != null && gcmMessage != null) { ((TextView) findViewById(R.id.textGcmIntent)).setText(gcmTitle + " / " + gcmMessage); } } private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000; private boolean hasPlayServices() { int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); if (resultCode != ConnectionResult.SUCCESS) { if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) { GooglePlayServicesUtil.getErrorDialog(resultCode, this, PLAY_SERVICES_RESOLUTION_REQUEST).show(); } else { Log.e(Const.TAG, "This device is not supported."); finish(); } return false; } return true; } } |
config/Const.java
「SENDER_ID」はGoogle Developers Consoleの「プロジェクト番号」に書き換えること。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
package jp.example.android.gcmarduino.config; public class Const { //SENDER_ID Google Developers Console "Project Number" public static final String SENDER_ID = "<<YOUR-SENDER-ID>>"; public static final String TAG = "gcmarduinotag"; public static final String INTENT_GCM_REGISTRATION = "INTENT_GCM_REGISTRATION"; public static final String EXTRA_GCM_REGISTERED = "EXTRA_GCM_REGISTERED"; public static final String EXTRA_GCM_REGISTRATION_ID = "EXTRA_GCM_REGISTRATION_ID"; public static final String EXTRA_GCM_TITLE = "EXTRA_GCM_TITLE"; public static final String EXTRA_GCM_MESSAGE = "EXTRA_GCM_MESSAGE"; public static final String GCM_TITLE_RINGTONE = "yellow"; public static final String GCM_TITLE_NOTIFICATION = "blue"; public static final String GCM_TITLE_ALARM = "green"; } |
gcm/MyGcmListenerService.java
GCMからメッセージが届いた場合の処理+通知を表示する処理を記述する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
package jp.example.android.gcmarduino.gcm; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.media.RingtoneManager; import android.os.Bundle; import android.support.v4.app.NotificationCompat; import android.util.Log; import com.google.android.gms.gcm.GcmListenerService; import jp.example.android.gcmarduino.activity.MainActivity; import jp.example.android.gcmarduino.config.Const; import jp.example.android.gcmarduino.R; /** * https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmListenerService */ public class MyGcmListenerService extends GcmListenerService { /** * receive message from GCM Communication Server */ @Override public void onMessageReceived(String from, Bundle bundle) { /* "data" property from received { "registration_ids": ["REGID1", "REGID2"], "data": {"title":"Yellow", "message":"YELLOW!"} } */ String title = bundle.getString("title"); String message = bundle.getString("message"); Log.i(Const.TAG, "MyGcmListenerService onMessageReceived()"); Log.i(Const.TAG, "title: " + title); Log.i(Const.TAG, "message: " + message); sendNotification(title, message); } private void sendNotification(String title, String message) { Intent intent = new Intent(this, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.putExtra(Const.EXTRA_GCM_TITLE, title); intent.putExtra(Const.EXTRA_GCM_MESSAGE, message); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT); NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this) //notification icon. this time use Google+ icon. .setSmallIcon(R.drawable.common_signin_btn_icon_dark) .setContentTitle(title) .setContentText(message) .setContentInfo("from GCM") .setAutoCancel(true) .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALL)) .setContentIntent(pendingIntent); //set notification sound if (Const.GCM_TITLE_RINGTONE.toLowerCase().equals(title.toLowerCase())) { notificationBuilder.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)); } else if (Const.GCM_TITLE_NOTIFICATION.toLowerCase().equals(title.toLowerCase())) { notificationBuilder.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)); } else if (Const.GCM_TITLE_ALARM.toLowerCase().equals(title.toLowerCase())) { notificationBuilder.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM)); } ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).notify(0, notificationBuilder.build()); } } |
gcm/MyGcmRegistrationIntentService.java
GCM側に端末のREGISTRATION_IDを登録する処理を記述する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
package jp.example.android.gcmarduino.gcm; import android.app.IntentService; import android.content.Intent; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import com.google.android.gms.gcm.GoogleCloudMessaging; import com.google.android.gms.iid.InstanceID; import java.io.IOException; import jp.example.android.gcmarduino.config.Const; /** * get REGISTRATION_ID using InstanceID API class */ public class MyGcmRegistrationIntentService extends IntentService { public MyGcmRegistrationIntentService() { super("MyGcmRegistrationIntentService"); } @Override protected void onHandleIntent(Intent intent) { Log.i(Const.TAG, getClass().getSimpleName() + " onHandleIntent()"); InstanceID instanceId = InstanceID.getInstance(this); boolean isGsmRegistered = false; //token = REGISTRATION_ID String registrationId = ""; try { registrationId = instanceId.getToken(Const.SENDER_ID, GoogleCloudMessaging.INSTANCE_ID_SCOPE); isGsmRegistered = true; } catch (IOException e) { //e.printStackTrace(); Log.e(Const.TAG, "cannot retrieve token", e); } Intent intentGcmRegistration = new Intent(Const.INTENT_GCM_REGISTRATION); intentGcmRegistration.putExtra(Const.EXTRA_GCM_REGISTERED, isGsmRegistered); intentGcmRegistration.putExtra(Const.EXTRA_GCM_REGISTRATION_ID, registrationId); LocalBroadcastManager.getInstance(this).sendBroadcast(intentGcmRegistration); } } |
gcm/MyInstanceIdListenerService.java
アプリの再インストール時などにGCM側からREGISTRATION_IDのリフレッシュがかかるらしいので、それを受け取るための処理(onTokenRefresh())を記述する。
GCM側からどういった場合にどういう命令?が飛んでくるのかはよくわからない。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
package jp.example.android.gcmarduino.gcm; import android.content.Intent; import android.util.Log; import com.google.android.gms.iid.InstanceIDListenerService; import jp.example.android.gcmarduino.config.Const; /** * https://developers.google.com/android/reference/com/google/android/gms/iid/InstanceIDListenerService */ public class MyInstanceIdListenerService extends InstanceIDListenerService { @Override public void onTokenRefresh() { Log.i(Const.TAG, getClass().getSimpleName() + " onTokenRefresh()"); Intent intent = new Intent(this, MyGcmRegistrationIntentService.class); startService(intent); } } |
lib/Util.java
1 2 3 4 5 6 7 8 9 10 11 12 13 |
package jp.example.android.gcmarduino.lib; import android.content.Context; import android.util.Log; import android.widget.Toast; import jp.example.android.gcmarduino.config.Const; public class Util { public static void toast(Context context, CharSequence message) { Toast.makeText(context, message, Toast.LENGTH_LONG).show(); Log.w(Const.TAG, message.toString()); } } |
res/strings.xml
1 2 3 |
<resources> <string name="app_name">GcmArduino</string> </resources> |
build.gradle(Module: app)
「dependencies」に「play-services-gcm」を追加する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
apply plugin: 'com.android.application' android { compileSdkVersion 22 buildToolsVersion "23.0.0 rc2" defaultConfig { applicationId "jp.example.android.gcmarduino" minSdkVersion 9 targetSdkVersion 22 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:22.2.0' compile 'com.google.android.gms:play-services-gcm:7.5.0' } |
Arduino側
上記GcmArduinoアプリで取得したREGISTRATION_IDをGoogleCloudMessaging.inoの「REGISTRATION_IDS[]」にコピペし、メッセージ送信先端末の識別子として利用する。
配線
ソースコード(GoogleCloudMessaging.ino)
・タクトスイッチの入力はArduino側でプルアップ(INPUT_PULLUP)にしておく。
・「ip[]」と「mac[]」は適宜変更すること。
・「YOUR-API-KEY」はGoogle Developers Consoleで作成したAPIキーに書き換えること。
・「REGISTRATION_IDS[]」の「REGID1」と「REGID2」はGcmArduinoアプリで取得したREGISTRATION_IDに書き換えること。
・SSLの通信はできないので、送信先のポートは443ではなくて80(httpのまま)に送る。
・ポインタとかハイレツとかよくわからないのでよしなに。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
#include <SPI.h> #include <Ethernet.h> //for PROGMEM #include <avr/pgmspace.h> //for Tact Switches #define PIN_INPUT_TACT_SW_YELLOW 9 #define PIN_INPUT_TACT_SW_BLUE 8 #define PIN_INPUT_TACT_SW_GREEN 7 //for Dip Rotary Coded Switch(0-F real-code) #define PIN_INPUT_ROTARY_SW_1 3 #define PIN_INPUT_ROTARY_SW_2 5 #define PIN_INPUT_ROTARY_SW_4 2 #define PIN_INPUT_ROTARY_SW_8 6 //MAC address (setting required) byte mac[] = {0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; //local IP address (setting required) byte ip[] = {192, 168, 0, 123}; //API key on Google Developers Console (setting required) PROGMEM char* const API_KEY = "YOUR-API-KEY"; //copy&paste REGISTRATION_ID from GcmArduino Android app (setting required) PROGMEM char* const REGISTRATION_IDS[] = { "REGID1", "REGID2", }; //REGISTRATION_IDS count (setting required) int registrationIdCount = 2; //// EthernetClient client; bool bYellow = false; bool bBlue = false; bool bGreen = false; //INPUT int inYellow = 0; int inBlue = 0; int inGreen = 0; PROGMEM char* const HOST = "android.googleapis.com"; //for json (A + REGISTRATION_ID + B + title + C + message + D) PROGMEM char* const A = "{\"registration_ids\":["; PROGMEM char* const B = "],\"data\":{\"title\":\""; PROGMEM char* const C = "\",\"message\":\""; PROGMEM char* const D = "\"}}"; PROGMEM char* const QUOTE = "\""; PROGMEM char* const COMMA = ","; PROGMEM char* const NONE = ""; void setup() { //tact switches pinMode as pullup (active-low) pinMode(PIN_INPUT_TACT_SW_YELLOW, INPUT_PULLUP); pinMode(PIN_INPUT_TACT_SW_BLUE, INPUT_PULLUP); pinMode(PIN_INPUT_TACT_SW_GREEN, INPUT_PULLUP); //dip rotary switch pinMode(PIN_INPUT_ROTARY_SW_1, INPUT); pinMode(PIN_INPUT_ROTARY_SW_2, INPUT); pinMode(PIN_INPUT_ROTARY_SW_4, INPUT); pinMode(PIN_INPUT_ROTARY_SW_8, INPUT); Serial.begin(9600); delay(500); while (!Serial) { ; } delay(1000); Ethernet.begin(mac, ip); delay(1000); Serial.print(F("IP: ")); Serial.println(Ethernet.localIP()); Serial.println(F("Ready...")); } void loop() { //read tact switches input (select message) inYellow = digitalRead(PIN_INPUT_TACT_SW_YELLOW); inBlue = digitalRead(PIN_INPUT_TACT_SW_BLUE); inGreen = digitalRead(PIN_INPUT_TACT_SW_GREEN); //read dip rotary switch input (select target device) int in1 = digitalRead(PIN_INPUT_ROTARY_SW_1); int in2 = digitalRead(PIN_INPUT_ROTARY_SW_2); int in4 = digitalRead(PIN_INPUT_ROTARY_SW_4); int in8 = digitalRead(PIN_INPUT_ROTARY_SW_8); //set target device int target = 0; if (in1 == 0 && in2 == 1) { //device2 target = 2; } else if (in1 == 1 && in2 == 0) { //device1 target = 1; } else { //device1, device2 target = 0; } switch (inYellow) { case LOW: //active-low if (!bYellow) { bYellow = true; //send message to target device send("Yellow", "YELLOW!", target); } break; default: bYellow = false; break; } switch (inBlue) { case LOW: //active-low if (!bBlue) { bBlue = true; //send message to target device send("Blue", "BLUE!", target); } break; default: bBlue = false; break; } switch (inGreen) { case LOW: //active-low if (!bGreen) { bGreen = true; //send message to target device send("Green", "GREEN!", target); } break; default: bGreen = false; break; } // while (client.available()) { // char c = client.read(); // Serial.print(c); // } // if (!client.connected()) { // client.stop(); // } } /** * send message to target device */ bool send(char* title, char* message, int target) { char* host = (char*) pgm_read_word(&HOST); //NOT https! if (client.connect(host, 80)) { char* postData = createPostData(title, message, target); //POST request client.println(F("POST /gcm/send HTTP/1.1")); client.print(F("Host: ")); client.println(host); client.println(F("User-Agent: Arduino")); client.println(F("Content-Type: application/json")); client.print(F("Authorization: key=")); char* regIds = (char*) pgm_read_word(&API_KEY); client.println(regIds); client.print(F("Content-Length: ")); client.println(strlen(postData)); client.println(F("Connection: close")); client.println(); client.print(postData); Serial.print(F("title="));Serial.println(title); Serial.print(F("target="));Serial.println(target); Serial.println(postData); Serial.println(F("sent")); delay(100); client.stop(); return true; } return false; } char* createPostData(char* title, char* message, int target) { const char* a = (char*) pgm_read_word(&A); const char* b = (char*) pgm_read_word(&B); const char* c = (char*) pgm_read_word(&C); const char* d = (char*) pgm_read_word(&D); const char* quote = (char*) pgm_read_word("E); const char* comma = (char*) pgm_read_word(&COMMA); const char* none = (char*) pgm_read_word(&NONE); char buf[512]; char tmp[464]; if (target == 0) { strcpy(tmp, none); for (int i = 0; i < registrationIdCount; i++) { const char* regId = (char*) pgm_read_word(®ISTRATION_IDS[i]); strcat(tmp, quote); strcat(tmp, regId); strcat(tmp, quote); if (i != (registrationIdCount - 1)) { strcat(tmp, comma); } } } else { const char* regId = (char*) pgm_read_word(®ISTRATION_IDS[target - 1]); strcpy(tmp, none); strcat(tmp, quote); strcat(tmp, regId); strcat(tmp, quote); } strcpy(buf, a); strcat(buf, tmp); strcat(buf, b); strcat(buf, title); strcat(buf, c); strcat(buf, message); strcat(buf, d); return buf; } |
動かしてみる
右の端末がdevice1(DIPが1の時に鳴る方)
左の端末(白)がdevice2(DIPが2の時に鳴る方)
1回目:黄色スイッチでdevice1,device2両方にメッセージが飛ぶ
2回目:青色スイッチでdevice1(右)だけにメッセージが飛ぶ
3回目:緑色スイッチでdevice2(左)だけにメッセージが飛ぶ