Skip to content

Commit d0126ea

Browse files
committed
DeviceControl: re-send packets until outlet toggles
1 parent 558f8a8 commit d0126ea

File tree

3 files changed

+92
-6
lines changed

3 files changed

+92
-6
lines changed

res/values-de/strings.xml

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
<string name="error_outlet_config_name">Bitte geben Sie für jede Steckdose eine Bezeichnung ein.</string>
2727
<string name="error_outlet_config_number">Bitte geben Sie gültige Nummern ein.</string>
2828
<string name="error_port_config_number">Bitte geben Sie eine gültige Port-Nummer ein.</string>
29+
<string name="error_getting_first_packet">Keine Antwort vom Gerät. Entweder die Ports sind falsch konfiguriert oder das Gerät ist nicht erreichbar. Sie können versuchen, Kommandos zu schicken, aber ob\'s was nützt, ist nicht sicher.</string>
30+
<string name="error_setting_outlet">Keine Antwort vom Gerät oder Sie haben keine Berechtigung, diese Steckdose zu schalten.</string>
2931

3032
<string name="device_settings">Geräte-Einstellungen</string>
3133
<string name="device_name">Name</string>

res/values/strings.xml

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
<string name="error_outlet_config_name">Please enter a description for every outlet.</string>
2727
<string name="error_outlet_config_number">Please enter only valid outlet numbers.</string>
2828
<string name="error_port_config_number">Please enter only valid port numbers.</string>
29+
<string name="error_getting_first_packet">No answer from the device. Either the ports are not configured correctly or it is out of reach. You may try sending comands, but the result is uncertain.</string>
30+
<string name="error_setting_outlet">No answer from the device or you don\'t gave the required permission to switch the outlet.</string>
2931

3032
<string name="device_settings">Device Settings</string>
3133
<string name="device_name">Name</string>

src/oly/netpowerctrl/DeviceControl.java

+88-6
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import java.net.DatagramSocket;
66
import java.net.InetAddress;
77
import java.util.ArrayList;
8+
import java.util.HashMap;
89
import java.util.List;
10+
import java.util.Map;
911

1012
import android.animation.ObjectAnimator;
1113
import android.annotation.SuppressLint;
@@ -17,6 +19,7 @@
1719
import android.os.Build;
1820
import android.os.Bundle;
1921
import android.os.Handler;
22+
import android.os.Message;
2023
import android.support.v4.content.LocalBroadcastManager;
2124
import android.view.Menu;
2225
import android.view.MenuItem;
@@ -33,15 +36,22 @@
3336

3437
public class DeviceControl extends Activity implements OnClickListener {
3538

39+
final Activity _this = this;
3640
DeviceInfo device;
3741
List<CompoundButton> buttons;
3842
ImageView imgReceive;
43+
boolean firstPacketReceived = false;
44+
45+
// for remembering what the device sent back
46+
Map<Integer,Boolean> lastreceivedState;
3947

4048
/** Called when the activity is first created. */
4149
@SuppressLint("NewApi")
4250
@Override
4351
public void onCreate(Bundle savedInstanceState) {
4452
super.onCreate(savedInstanceState);
53+
54+
lastreceivedState = new HashMap<Integer,Boolean>();
4555

4656
Intent it = new Intent(this, NetpowerctrlService.class);
4757
startService(it);
@@ -90,6 +100,7 @@ public void onCreate(Bundle savedInstanceState) {
90100
if (Build.VERSION.SDK_INT >= 14)
91101
cb = new Switch(this);
92102
else cb = new CheckBox(this);
103+
cb.setEnabled(false); // will only be enabled when the first answer arrives
93104
cb.setChecked(oi.State);
94105
cb.setTag(oi.OutletNumber);
95106
cb.setText(oi.Description);
@@ -105,8 +116,15 @@ public void onCreate(Bundle savedInstanceState) {
105116
@Override
106117
protected void onResume() {
107118
super.onResume();
119+
120+
// disable all buttons, will be re-enabled when the first answer arrives
121+
for (View v: buttons)
122+
v.setEnabled(false);
123+
108124
IntentFilter itf= new IntentFilter(DiscoveryThread.BROADCAST_DEVICE_DISCOVERED);
109125
LocalBroadcastManager.getInstance(this).registerReceiver(onDeviceDiscovered, itf);
126+
firstPacketReceived = false;
127+
onFirstPacketCheck.sendMessageDelayed(onFirstPacketCheck.obtainMessage(), 2000); // after 2 seconds, check if no packet was received and display the respective dialog
110128
DeviceQuery.sendQuery(this, device.HostName, device.SendPort);
111129
}
112130

@@ -139,7 +157,10 @@ public boolean onCreateOptionsMenu(Menu menu) {
139157
public void onClick(View v) {
140158
int outletNumber = (Integer)v.getTag();
141159
if (outletNumber >= 0) {
142-
sendOutlet(outletNumber, ((CompoundButton)v).isChecked());
160+
boolean new_state = ((CompoundButton)v).isChecked();
161+
AfterSentHandler ash = new AfterSentHandler(outletNumber, new_state);
162+
ash.sendMessageDelayed(ash.obtainMessage(), 500); // check after 500 ms
163+
sendOutlet(outletNumber, new_state);
143164
} else {
144165
Toast.makeText(this,
145166
getResources().getString(R.string.error_outlet_number),
@@ -200,13 +221,15 @@ public void onReceive(Context context, Intent intent) {
200221

201222
// our device?
202223
if (device.MacAddress.equals(device_info.MacAddress)) {
224+
// remember this state
225+
lastreceivedState.clear();
226+
for (OutletInfo oi: device_info.Outlets)
227+
lastreceivedState.put(oi.OutletNumber, oi.State);
228+
203229
// update outlet states
204230
for (CompoundButton button: buttons) {
205-
for (OutletInfo oi: device_info.Outlets) {
206-
if (oi.OutletNumber == (Integer)button.getTag()) {
207-
button.setChecked(oi.State);
208-
}
209-
}
231+
if (lastreceivedState.containsKey((Integer)button.getTag()))
232+
button.setChecked(lastreceivedState.get((Integer)button.getTag()));
210233
}
211234
if (Build.VERSION.SDK_INT >= 11) {
212235
ObjectAnimator anim = ObjectAnimator.ofFloat(imgReceive, "Alpha", 0, 1, 0);
@@ -221,8 +244,67 @@ public void run() {
221244
}
222245
}, 400);
223246
}
247+
248+
// re-enable all buttons
249+
for (View v: buttons)
250+
v.setEnabled(true);
251+
firstPacketReceived = true; // some way, every packet is the first packet ;-)
252+
224253
}
225254
}
226255
};
256+
257+
private Handler onFirstPacketCheck= new Handler() {
258+
public void handleMessage(Message m) {
259+
if (! firstPacketReceived) {
260+
Toast.makeText(_this, getResources().getString(R.string.error_getting_first_packet), Toast.LENGTH_LONG).show();
261+
for (View v: buttons)
262+
v.setEnabled(true);
263+
}
264+
}
265+
};
266+
267+
private class AfterSentHandler extends Handler {
268+
int outletNumber; // remember for which outlet we were started
269+
boolean state; // the state we want the outlet to be in
270+
int retries;
271+
272+
public AfterSentHandler(int outletNr, boolean expected_state) {
273+
outletNumber = outletNr;
274+
state = expected_state;
275+
retries = 0;
276+
}
277+
278+
public void handleMessage(Message m) {
279+
if (retries > 3) {
280+
//give up
281+
Toast.makeText(_this, getResources().getString(R.string.error_setting_outlet), Toast.LENGTH_LONG).show();
282+
return;
283+
}
284+
285+
if (lastreceivedState.containsKey(outletNumber)) {
286+
if (lastreceivedState.get(outletNumber) != state) {
287+
retries++;
288+
sendMessageDelayed(obtainMessage(), 500); // check again after 500 ms
289+
sendOutlet(outletNumber, state);
290+
// show the current state
291+
for (CompoundButton button: buttons) {
292+
if ((Integer)button.getTag() == outletNumber) {
293+
button.setChecked(!state);
294+
}
295+
}
296+
}
297+
298+
} else {
299+
// nothing received yet, try again
300+
retries++;
301+
sendMessageDelayed(obtainMessage(), 500); // check again after 500 ms
302+
sendOutlet(outletNumber, state);
303+
}
304+
}
305+
306+
}
307+
308+
227309

228310
}

0 commit comments

Comments
 (0)