From 0b72adcd3a141834ba5fbb647f229ea43cc24165 Mon Sep 17 00:00:00 2001 From: strawmanbobi Date: Thu, 29 Jan 2026 10:29:35 +0800 Subject: [PATCH] added remote control feedback info --- android-example/README.md | 53 +++++++++++++++++-- .../ircontrol/controller/ArduinoRemote.java | 44 ++++++++++----- .../ircontrol/controller/PhoneRemote.java | 10 +++- .../ui/fragment/ControlFragment.java | 30 ++++++++--- .../src/main/res/values-zh-rCN/strings.xml | 2 + .../app/src/main/res/values/strings.xml | 2 + arduino-example/README.md | 1 + arduino-example/src/main.cpp | 9 +++- 8 files changed, 125 insertions(+), 26 deletions(-) create mode 100644 arduino-example/README.md diff --git a/android-example/README.md b/android-example/README.md index dd64ec3..922da57 100644 --- a/android-example/README.md +++ b/android-example/README.md @@ -1,5 +1,52 @@ -# irext-example-android -IR decode example for Android application +# IRext Android APP Example -Please refer to the usage documents in /decodesdk +This project shows how can you develop an Android APP remote controller quickly. +The key components of the Android remote example includes: + +## The Cloud-SDK +The Cloud SDK calls the Rest API provided by the IRext index service to complete the APP login and +help use indexing targeted remote controller from category to remote index. + +To import the Android Cloud SDK, add following line to the build.gradle for the APP + +``` +implementation 'net.irext.webapi:irext-androidapi:1.5.2 +``` + +And then add the meta-data in your AndroidManifest.xml to make the Cloud SDK login to the indexing server for the access token + +```xml + + + + +``` + +Follow the examples of calling `mApp.mWeAPIs` in corresponding UI flows in order to find the targeted remote index, download the remote control binary file. + +## Use Mobile Phone as Remote Control +After the remote index binary code is downloaded, you can see the remote control panel, +by pressing control buttons, the binary code would be decoded into IR timing series. If you have an Android phone with IR transmitter, +you can send the 38KHz infra-red waves directly to control the home appliances. + +As a reference, you need to integrate the IR decode library, see the shared libraries in jniLibs directory into your project. + +By calling API provided by the decode library in order to open and decode remote control binary files into infra-red timing series: + +```java + +``` + +## Working with Arduino Remote Control +There is another example project arduino-example which can be co-worked with this +Android APP remote controller. + + +Well by connecting to the Arduino controller with IP address in the same LAN, the Android APP can send the downloaded remote control binary to it, +and then pass the remote control command by pressing buttons accordingly. The Arduino remote controller would decode the IR time series instead and send the +38KHz infra-red carrier waves to home appliances. \ No newline at end of file diff --git a/android-example/app/src/main/java/net/irext/ircontrol/controller/ArduinoRemote.java b/android-example/app/src/main/java/net/irext/ircontrol/controller/ArduinoRemote.java index 1fcafcd..3db802e 100644 --- a/android-example/app/src/main/java/net/irext/ircontrol/controller/ArduinoRemote.java +++ b/android-example/app/src/main/java/net/irext/ircontrol/controller/ArduinoRemote.java @@ -15,6 +15,9 @@ import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.util.Base64; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; /** * Filename: ArduinoRemote.java @@ -44,6 +47,12 @@ public class ArduinoRemote extends Remote { public static final String A_REQUEST_CTRL = "a_control"; public static final String E_RESPONSE_CTRL = "e_control"; + public static final String E_INDICATION_SUCCESS = "e_success"; + + public static final String E_INDICATION_FAILED = "e_failed"; + + private static final int CONTROL_COMMAND_TIMEOUT = 5; + private Socket emitterConn = null; private int connectionStatus = EMITTER_DISCONNECTED; private IRSocketEmitterCallback callback; @@ -98,7 +107,7 @@ public class ArduinoRemote extends Remote { connectionStatus = EMITTER_CONNECTED; onConnected(); - + BufferedReader in = new BufferedReader(new InputStreamReader(emitterConn.getInputStream())); String response; while ((response = in.readLine()) != null) { @@ -167,18 +176,14 @@ public class ArduinoRemote extends Remote { } public void sendControlToEmitter(String command) { - String commandStr = A_REQUEST_CTRL + "," + command.length() + "," + command; - Log.d(TAG, "sending command in base64: " + commandStr); - new Thread(() -> { - try { - PrintWriter out = new PrintWriter(emitterConn.getOutputStream(), true); - out.println(commandStr); - } catch (IOException e) { - Log.e(TAG, "Error sending control data: " + e.getMessage()); - } - }).start(); + try { + PrintWriter out = new PrintWriter(emitterConn.getOutputStream(), true); + out.println(commandStr); + } catch (IOException e) { + Log.e(TAG, "Error sending control data: " + e.getMessage()); + } } public void sendDecodedToEmitter(String binContent) { @@ -200,20 +205,23 @@ public class ArduinoRemote extends Remote { } private void onResponse(String response) { + Log.d(TAG, "the emitter is response: " + response); if (response.startsWith(ArduinoRemote.E_RESPONSE_HELLO)) { Log.d(TAG, "received e_hello"); } else if (response.startsWith(ArduinoRemote.E_RESPONSE_BIN)) { Log.d(TAG, "received e_bin"); } else if (response.startsWith(ArduinoRemote.E_RESPONSE_CTRL)) { connectionStatus = EMITTER_WORKING; + } else if (response.startsWith(ArduinoRemote.E_INDICATION_SUCCESS) || + response.startsWith(ArduinoRemote.E_INDICATION_FAILED)) { + Log.d(TAG, "received control indication : " + response); } else { Log.e(TAG, "unexpected response : " + response); } callback.onResponse(response); } - - public void irControl(int category, int subCategory, int keyCode) { + public int irControl(int category, int subCategory, int keyCode) { Log.d(TAG, "irControl, category = " + category + ", subCategory = " + subCategory + ", keyCode = " + keyCode); @@ -223,8 +231,16 @@ public class ArduinoRemote extends Remote { ArduinoControlCommand command = new ArduinoControlCommand(inputKeyCode, acStatus); String controlCommand = command.toString(); - sendControlToEmitter(controlCommand); + new Thread(() -> { + try { + sendControlToEmitter(controlCommand); + } catch (Exception e) { + callback.onResponse(E_INDICATION_FAILED); + } + }).start(); + + return 0; } private static class ArduinoControlCommand extends ControlCommand { diff --git a/android-example/app/src/main/java/net/irext/ircontrol/controller/PhoneRemote.java b/android-example/app/src/main/java/net/irext/ircontrol/controller/PhoneRemote.java index e0f105f..63f3609 100644 --- a/android-example/app/src/main/java/net/irext/ircontrol/controller/PhoneRemote.java +++ b/android-example/app/src/main/java/net/irext/ircontrol/controller/PhoneRemote.java @@ -28,7 +28,7 @@ public class PhoneRemote extends Remote { public PhoneRemote(Context context) { mContext = context; - mIRDecode = new IRDecode(); + mIRDecode = IRDecode.getInstance(); } public static PhoneRemote getInstance(Context context) { @@ -38,6 +38,10 @@ public class PhoneRemote extends Remote { return mInstance; } + public int irOpen(String remoteBinFilePath, int category, int subCategory) { + return mIRDecode.openFile(category, subCategory, remoteBinFilePath); + } + public int irControl(int category, int subCategory, int keyCode) { int []decoded; StringBuilder debugStr = new StringBuilder(); @@ -55,4 +59,8 @@ public class PhoneRemote extends Remote { ControlHelper.transmitIr(mContext, decoded); return 0; } + + public void irClose() { + mIRDecode.closeBinary(); + } } diff --git a/android-example/app/src/main/java/net/irext/ircontrol/ui/fragment/ControlFragment.java b/android-example/app/src/main/java/net/irext/ircontrol/ui/fragment/ControlFragment.java index 62508a1..d48388b 100644 --- a/android-example/app/src/main/java/net/irext/ircontrol/ui/fragment/ControlFragment.java +++ b/android-example/app/src/main/java/net/irext/ircontrol/ui/fragment/ControlFragment.java @@ -54,8 +54,6 @@ public class ControlFragment extends Fragment implements View.OnClickListener { private Long mRemoteID; private RemoteControl mCurrentRemoteControl; - // define the single instance of IRDecode - private IRDecode mIRDecode; private EditText mEtEmitterIp; private ImageButton mBtnConnect; private View mVWConnectStatus; @@ -67,7 +65,6 @@ public class ControlFragment extends Fragment implements View.OnClickListener { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - mIRDecode = IRDecode.getInstance(); mHandler = new MsgHandler(this); mParent = (ControlActivity)getActivity(); @@ -179,13 +176,13 @@ public class ControlFragment extends Fragment implements View.OnClickListener { mCurrentRemoteControl.getRemoteMap() + FileUtils.FILE_NAME_EXT; /* decode SDK - load binary file */ - int ret = mIRDecode.openFile(category, mCurrentRemoteControl.getSubCategory(), binFileName); + int ret = mPhoneRemote.irOpen(binFileName, category, mCurrentRemoteControl.getSubCategory()); Log.d(TAG, "binary opened : " + ret); } } public void closeIRBinary() { - mIRDecode.closeBinary(); + mPhoneRemote.irClose(); } private void onEmitterConnected() { @@ -221,7 +218,17 @@ public class ControlFragment extends Fragment implements View.OnClickListener { } private void processECtrl(String response) { - ; + + } + + private void processControlResult(String response) { + mParent.runOnUiThread(() -> { + if (response.startsWith(ArduinoRemote.E_INDICATION_SUCCESS)) { + ToastUtils.showToast(mParent, mParent.getString(R.string.decode_and_send_success), null); + } else { + ToastUtils.showToast(mParent, mParent.getString(R.string.decode_and_send_failed), null); + } + }); } private void onEmitterResponse(String response) { @@ -231,6 +238,9 @@ public class ControlFragment extends Fragment implements View.OnClickListener { processEBin(response); } else if (response.startsWith(ArduinoRemote.E_RESPONSE_CTRL)) { processECtrl(response); + } else if (response.startsWith(ArduinoRemote.E_INDICATION_SUCCESS) || + response.startsWith(ArduinoRemote.E_INDICATION_FAILED)) { + processControlResult(response); } else { Log.e(TAG, "unexpected response : " + response); } @@ -242,6 +252,7 @@ public class ControlFragment extends Fragment implements View.OnClickListener { vibrate(mParent); Remote remote = null; int keyCode = 0; + int result = 0; int id = v.getId(); if (id == R.id.iv_power) { keyCode = Remote.KEY_POWER; @@ -270,7 +281,12 @@ public class ControlFragment extends Fragment implements View.OnClickListener { if (mArduinoRemote.getConnectionStatus() == ArduinoRemote.EMITTER_WORKING) { mArduinoRemote.irControl(mCurrentRemoteControl.getCategoryId(), mCurrentRemoteControl.getSubCategory(), keyCode); } else { - mPhoneRemote.irControl(mCurrentRemoteControl.getCategoryId(), mCurrentRemoteControl.getSubCategory(), keyCode); + result = mPhoneRemote.irControl(mCurrentRemoteControl.getCategoryId(), mCurrentRemoteControl.getSubCategory(), keyCode); + if (0 == result) { + ToastUtils.showToast(mParent, mParent.getString(R.string.decode_and_send_success), null); + } else { + ToastUtils.showToast(mParent, mParent.getString(R.string.decode_and_send_failed), null); + } } } diff --git a/android-example/app/src/main/res/values-zh-rCN/strings.xml b/android-example/app/src/main/res/values-zh-rCN/strings.xml index 71208bd..8e7f163 100644 --- a/android-example/app/src/main/res/values-zh-rCN/strings.xml +++ b/android-example/app/src/main/res/values-zh-rCN/strings.xml @@ -45,5 +45,7 @@ 未连接 已连接 编码文件无法打开 + 遥控码发送成功 + 遥控失败 diff --git a/android-example/app/src/main/res/values/strings.xml b/android-example/app/src/main/res/values/strings.xml index 3e8b043..7cede8a 100644 --- a/android-example/app/src/main/res/values/strings.xml +++ b/android-example/app/src/main/res/values/strings.xml @@ -45,5 +45,7 @@ Disconnected Connected The IR binary file could not be opened + Remote control code sent + Remote control failed diff --git a/arduino-example/README.md b/arduino-example/README.md new file mode 100644 index 0000000..06ed334 --- /dev/null +++ b/arduino-example/README.md @@ -0,0 +1 @@ +# IRext Arduino Example diff --git a/arduino-example/src/main.cpp b/arduino-example/src/main.cpp index 41254e8..b8b7137 100644 --- a/arduino-example/src/main.cpp +++ b/arduino-example/src/main.cpp @@ -48,6 +48,8 @@ auto *aControl = "a_control"; auto *eControl = "e_control"; auto *aError = "a_error"; auto *eError = "e_error"; +auto *eControlSuccess = "e_success"; +auto *eControlFailed = "e_failed"; int status = WL_IDLE_STATUS; unsigned long lastStatusCheck = 0; @@ -172,7 +174,12 @@ void onCommand(WiFiClient *client, const String *command) { #endif } else if (command->startsWith(aControl)) { serialPrint(LOG_DEBUG, "Received control command"); - remoteControl(command->c_str()); + if (0 == remoteControl(command->c_str())) { + serialPrint(LOG_INFO, "Remote control successfully"); + sendToClient(client, eControlSuccess); + } else { + sendToClient(client, eControlFailed); + } } else if (command->startsWith(aError)) { serialPrint(LOG_DEBUG, "Received error command"); onError(client);