Slide 1

Slide 1 text

@MOLSJEROEN HOW TO BUILD A CONNECTED PRODUCT DEEP INTO THE IOT TRENCHES:

Slide 2

Slide 2 text

@MOLSJEROEN @MOLSJEROEN www.philips.com/careers-hue

Slide 3

Slide 3 text

IT’S NOT ENOUGH FOR CODE TO WORK. Robert C. Martin

Slide 4

Slide 4 text

@MOLSJEROEN BUILDING A CONNECTED PRODUCT

Slide 5

Slide 5 text

@MOLSJEROEN BUILDING A CONNECTED PRODUCT

Slide 6

Slide 6 text

@MOLSJEROEN BUILDING A CONNECTED PRODUCT

Slide 7

Slide 7 text

@MOLSJEROEN BUILDING A CONNECTED PRODUCT

Slide 8

Slide 8 text

@MOLSJEROEN BUILDING A CONNECTED PRODUCT

Slide 9

Slide 9 text

@MOLSJEROEN BUILDING A CONNECTED PRODUCT

Slide 10

Slide 10 text

@MOLSJEROEN BUILDING A CONNECTED PRODUCT

Slide 11

Slide 11 text

@MOLSJEROEN BUILDING A CONNECTED PRODUCT

Slide 12

Slide 12 text

@MOLSJEROEN BUILDING A CONNECTED PRODUCT

Slide 13

Slide 13 text

@MOLSJEROEN BUILDING A CONNECTED PRODUCT ?

Slide 14

Slide 14 text

@MOLSJEROEN CHALLENGES 1. Easy to use (and test) ▸ Wi-Fi setup ▸ Prepare for bad weather 2. Performant ▸ Fast discovery ▸ Maximise control speed 3. Scalable ▸ Lessons learned

Slide 15

Slide 15 text

@MOLSJEROEN CHALLENGES 1. Easy to use (and test) ▸ Wi-Fi setup ▸ Prepare for bad weather 2. Performant ▸ Fast discovery ▸ Maximise control speed 3. Scalable ▸ Lessons learned

Slide 16

Slide 16 text

WI-FI SETUP PART 1: EASY TO USE (AND TEST)

Slide 17

Slide 17 text

@MOLSJEROEN WI-FI SETUP - GOAL

Slide 18

Slide 18 text

@MOLSJEROEN WI-FI SETUP - GOAL ?

Slide 19

Slide 19 text

@MOLSJEROEN WI-FI SETUP - MECHANISM

Slide 20

Slide 20 text

@MOLSJEROEN WI-FI SETUP - MECHANISM

Slide 21

Slide 21 text

@MOLSJEROEN WI-FI SETUP - MECHANISM SSID & PASSWORD

Slide 22

Slide 22 text

@MOLSJEROEN WI-FI SETUP - MECHANISM

Slide 23

Slide 23 text

@MOLSJEROEN WI-FI SETUP - MECHANISM

Slide 24

Slide 24 text

@MOLSJEROEN WI-FI SETUP - CHROMECAST 4 3 2 1

Slide 25

Slide 25 text

@MOLSJEROEN WI-FI SETUP - CHROMECAST 4 3 2 1

Slide 26

Slide 26 text

@MOLSJEROEN WI-FI SETUP - CHROMECAST 4 3 2 1

Slide 27

Slide 27 text

@MOLSJEROEN WI-FI SETUP - CHROMECAST 8 7 6 5

Slide 28

Slide 28 text

@MOLSJEROEN WI-FI SETUP - CHROMECAST 8 7 6 5

Slide 29

Slide 29 text

@MOLSJEROEN WI-FI SETUP - CHROMECAST 8 7 6 5

Slide 30

Slide 30 text

@MOLSJEROEN WI-FI SETUP - CHROMECAST 12 11 10 9

Slide 31

Slide 31 text

@MOLSJEROEN WI-FI SETUP - CHROMECAST 12 11 10 9

Slide 32

Slide 32 text

@MOLSJEROEN WI-FI SETUP - CHROMECAST 12 11 10 9

Slide 33

Slide 33 text

@MOLSJEROEN WI-FI SETUP - CHROMECAST 12 11 10 9

Slide 34

Slide 34 text

@MOLSJEROEN WI-FI SETUP - CHALLENGES ▸ Typing Wi-Fi passwords ▸ Network switching is fragile ▸ phone/tablet refuses to connect ▸ OS routes request over 4G ▸ Extremely slow feedback ▸ Users have to leave app on iOS ▸ Many bad weather scenarios

Slide 35

Slide 35 text

@MOLSJEROEN WI-FI SETUP - CHALLENGES ▸ 1

Slide 36

Slide 36 text

IF WI-FI SETUP FAILS, YOUR PRODUCT WILL BE RETURNED Yours truly

Slide 37

Slide 37 text

@MOLSJEROEN ANDROID 5.0+ ▸ Behaviour change in Android 5.0 ▸ Wi-Fi without internet ▸ Before: all requests sent over Wi-Fi ▸ After: all requests routed over 3G/4G ▸ Done for all, no subnet matching

Slide 38

Slide 38 text

@MOLSJEROEN ANDROID 5.0+ - SINGLE REQUEST OVER WI-FI @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public void singleRequestOverWifi(Context context) { NetworkRequest.Builder request = new NetworkRequest.Builder(); request.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); ConnectivityManager connMan = getConnectivityManager(); connMan.registerNetworkCallback(request.build(), new NetworkCallback(){ @Override public void onAvailable(Network network) { // Do network request } }); }

Slide 39

Slide 39 text

@MOLSJEROEN ANDROID 5.0+ - SINGLE REQUEST OVER WI-FI @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public void singleRequestOverWifi(Context context) { NetworkRequest.Builder request = new NetworkRequest.Builder(); request.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); ConnectivityManager connMan = getConnectivityManager(); connMan.registerNetworkCallback(request.build(), new NetworkCallback(){ @Override public void onAvailable(Network network) { // Do network request } }); }

Slide 40

Slide 40 text

@MOLSJEROEN ANDROID 5.0+ - SINGLE REQUEST OVER WI-FI @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public void singleRequestOverWifi(Context context) { NetworkRequest.Builder request = new NetworkRequest.Builder(); request.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); ConnectivityManager connMan = getConnectivityManager(); connMan.registerNetworkCallback(request.build(), new NetworkCallback(){ @Override public void onAvailable(Network network) { // Do network request } }); }

Slide 41

Slide 41 text

@MOLSJEROEN ANDROID 5.0+ - SINGLE REQUEST OVER WI-FI @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public void singleRequestOverWifi(Context context) { NetworkRequest.Builder request = new NetworkRequest.Builder(); request.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); ConnectivityManager connMan = getConnectivityManager(); connMan.registerNetworkCallback(request.build(), new NetworkCallback(){ @Override public void onAvailable(Network network) { // Do network request } }); }

Slide 42

Slide 42 text

@MOLSJEROEN ANDROID 5.0+ - ALL REQUESTS OVER WI-FI @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public void allRequestsOverWifi(Context context) { NetworkRequest.Builder request = new NetworkRequest.Builder(); request.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); final ConnectivityManager connMan = getConnectivityManager(); connMan.registerNetworkCallback(request.build(), new NetworkCallback() { @Override public void onAvailable(Network network) { connMan.bindProcessToNetwork(network); // Do network requests } }); }

Slide 43

Slide 43 text

@MOLSJEROEN ANDROID 5.0+ - ALL REQUESTS OVER WI-FI @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public void allRequestsOverWifi(Context context) { NetworkRequest.Builder request = new NetworkRequest.Builder(); request.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); final ConnectivityManager connMan = getConnectivityManager(); connMan.registerNetworkCallback(request.build(), new NetworkCallback() { @Override public void onAvailable(Network network) { connMan.bindProcessToNetwork(network); // Do network requests } }); }

Slide 44

Slide 44 text

@MOLSJEROEN ALTERNATIVES ▸ One product as ethernet bridge ▸ WPS ▸ Other mechanisms for communication ▸ e.g High frequency sound, … ▸ Still need to enter Wi-Fi password ▸ WAC (Homekit devices) ▸ …

Slide 45

Slide 45 text

@MOLSJEROEN #PROTIP - RANDOM SETUP NETWORK NAME ssid
 SETUP ssid
 SETUP ssid
 SETUP ssid
 SETUP ????????

Slide 46

Slide 46 text

@MOLSJEROEN #PROTIP - RANDOM SETUP NETWORK NAME

Slide 47

Slide 47 text

PREPARE FOR BAD WEATHER PART 1: EASY TO USE (AND TEST)

Slide 48

Slide 48 text

@MOLSJEROEN GOOD WEATHER SCENARIOS

Slide 49

Slide 49 text

@MOLSJEROEN BAD WEATHER SCENARIOS

Slide 50

Slide 50 text

@MOLSJEROEN BAD WEATHER SCENARIOS

Slide 51

Slide 51 text

@MOLSJEROEN BAD WEATHER SCENARIOS

Slide 52

Slide 52 text

@MOLSJEROEN INTERESTING SCENARIOS ▸ Bridge (almost) full ▸ Network request failed for reason X ▸ Resource doesn’t exist ▸ Connection lost ▸ Authentication lost ▸ Dynamic state changes ▸ …. => nearly impossible to reproduce manually

Slide 53

Slide 53 text

@MOLSJEROEN SIMULATOR ▸ Hardcoded responses ▸ Simulate dynamic behaviour ▸ Recreate bad weather scenarios

Slide 54

Slide 54 text

@MOLSJEROEN SIMULATOR COMMUNICATIONSTRATEGY REMOTESTRATEGY LOCALSTRATEGY SIMULATORSTRATEGY PRODUCT 1.. ▸ Hardcoded responses ▸ Simulate dynamic behaviour ▸ Recreate bad weather scenarios

Slide 55

Slide 55 text

@MOLSJEROEN SIMULATOR COMMUNICATIONSTRATEGY REMOTESTRATEGY LOCALSTRATEGY SIMULATORSTRATEGY PRODUCT 1.. ▸ Hardcoded responses ▸ Simulate dynamic behaviour ▸ Recreate bad weather scenarios

Slide 56

Slide 56 text

@MOLSJEROEN #PROTIP - DON'T USE THE WORD “DEVICE” ▸ Use product or appliance

Slide 57

Slide 57 text

@MOLSJEROEN CHALLENGES 1. Easy to use (and test) ▸ Wi-Fi setup ▸ Prepare for bad weather 2. Performant ▸ Fast discovery ▸ Maximise control speed 3. Scalable ▸ Lessons learned

Slide 58

Slide 58 text

DISCOVERY PART 2: PERFORMANT

Slide 59

Slide 59 text

@MOLSJEROEN LOCAL DISCOVERY ▸ Multicast based ▸ Often Unicast responses ▸ SSDP, mDNS,…

Slide 60

Slide 60 text

@MOLSJEROEN LOCAL DISCOVERY ▸ Multicast based ▸ Often Unicast responses ▸ SSDP, mDNS,…

Slide 61

Slide 61 text

@MOLSJEROEN LOCAL DISCOVERY ▸ Multicast based ▸ Often Unicast responses ▸ SSDP, mDNS,…

Slide 62

Slide 62 text

@MOLSJEROEN LOCAL DISCOVERY ▸ Multicast based ▸ Often Unicast responses ▸ SSDP, mDNS,… ▸ Alternatives ▸ IP scan ▸ Manual IP ▸ Proprietary product IP server

Slide 63

Slide 63 text

@MOLSJEROEN LOCAL DISCOVERY - IP SERVER https://www.meethue.com/api/nupnp [ { "id":"001788fffe100491", “internalipaddress":"192.168.2.23" }, { "id":"001788fffe09a168", “internalipaddress":"192.168.88.252" } ]

Slide 64

Slide 64 text

@MOLSJEROEN REMOTE DISCOVERY ▸ Web service ▸ product announces ▸ interface to get products ▸ Security ▸ Local setup first required

Slide 65

Slide 65 text

@MOLSJEROEN OPTIMISING DISCOVERY

Slide 66

Slide 66 text

@MOLSJEROEN OPTIMISING DISCOVERY 1. Discover local and remote 2. Connect local and remote ▸ ~5 - 10 seconds ▸ Empty UI when no products found

Slide 67

Slide 67 text

@MOLSJEROEN OPTIMISING DISCOVERY - REMEMBER PRODUCTS 1. Products from database 2. Discover local and remote 3. Connect local and remote ▸ ~5 - 10 seconds ▸ Disconnected device when not found ▸ Need for deleting devices

Slide 68

Slide 68 text

@MOLSJEROEN OPTIMISING DISCOVERY - REMEMBER STATE 1. Products & last state from database 2. Discover local and remote 3. Connect local and remote 4. Update UI with actual state ▸ ~3 - 4 seconds ▸ UI instantly ready ▸ Control possible after discovery

Slide 69

Slide 69 text

@MOLSJEROEN OPTIMISING DISCOVERY - REMEMBER CONNECTION INFO 1. Products, last state & connection info from database 2. Attempt local and remote connection 3. Fallback discovery 4. Update UI with actual state ▸ ~0 seconds ▸ UI & Control instantly ready ▸ Remember IP address and last SSID

Slide 70

Slide 70 text

@MOLSJEROEN #PROTIP - SIMPLIFY DEVELOPMENT BY LIMITING STATE TRANSITIONS ▸ Transition local to remote connection always via disconnected

Slide 71

Slide 71 text

MAXIMISE CONTROL SPEED PART 2: PERFORMANT

Slide 72

Slide 72 text

@MOLSJEROEN CONTROL SPEED 1. Always prefer local connection 2. Optimise local connection 3. Reduce amount of requests 4. Instant UI ▸ Implicit cost savings ▸ Remote connection usually not critical

Slide 73

Slide 73 text

@MOLSJEROEN 1. PREFER LOCAL CONNECTION ▸ Inherently faster ▸ Cost benefit ▸ Force connection

Slide 74

Slide 74 text

@MOLSJEROEN 1. PREFER LOCAL CONNECTION COMPOSITESTRATEGY PRODUCT LOCALSTRATEGY SIMULATORSTRATEGY REMOTESTRATEGY COMMUNICATIONSTRATEGY - boolean isAvailable() ▸ Inherently faster ▸ Cost benefit ▸ Force connection

Slide 75

Slide 75 text

@MOLSJEROEN 2. OPTIMISE LOCAL CONNECTION ▸ Data compression ▸ Cache headers ▸ Socket reuse ▸ => OKHttp ▸ Interference UDP/TCP or other traffic ▸ Wireshark low level traffic

Slide 76

Slide 76 text

@MOLSJEROEN 2. OPTIMISE LOCAL CONNECTION ▸ Data compression ▸ Cache headers ▸ Socket reuse ▸ => OKHttp ▸ Interference UDP/TCP or other traffic ▸ Wireshark low level traffic

Slide 77

Slide 77 text

@MOLSJEROEN 3. REDUCE # REQUESTS ▸ Toggle sequences ▸ Combine requests to same endpoint

Slide 78

Slide 78 text

@MOLSJEROEN 3. REDUCE # REQUESTS private Map pendingAttr = new HashMap<>(); public void setOn(boolean isOn) { synchronized (pendingAttr) { pendingAttr("KEY_ON", isOn); } sendUpdate(); } private void sendUpdate() { strategy.doRequest(updateRequest); }

Slide 79

Slide 79 text

@MOLSJEROEN 3. REDUCE # REQUESTS private Map pendingAttr = new HashMap<>(); public void setOn(boolean isOn) { synchronized (pendingAttr) { pendingAttr("KEY_ON", isOn); } sendUpdate(); } private void sendUpdate() { strategy.doRequest(updateRequest); }

Slide 80

Slide 80 text

@MOLSJEROEN 3. REDUCE # REQUESTS private Map pendingAttr = new HashMap<>(); public void setOn(boolean isOn) { synchronized (pendingAttr) { pendingAttr("KEY_ON", isOn); } sendUpdate(); } private void sendUpdate() { strategy.doRequest(updateRequest); }

Slide 81

Slide 81 text

@MOLSJEROEN 3. REDUCE # REQUESTS private Map pendingAttr = new HashMap<>(); public void setOn(boolean isOn) { synchronized (pendingAttr) { pendingAttr("KEY_ON", isOn); } sendUpdate(); } private void sendUpdate() { strategy.doRequest(updateRequest); }

Slide 82

Slide 82 text

@MOLSJEROEN 3. REDUCE # REQUESTS private UpdateRequest updateRequest = new UpdateRequest() { @Override public String getEndpoint() { return "/lights"; } @Override public Map getAttributes() { synchronized (pendingAttr) { Map copy = new HashMap<>(pendingAttr); pendingAttr.clear(); return copy; } }};

Slide 83

Slide 83 text

@MOLSJEROEN 3. REDUCE # REQUESTS private UpdateRequest updateRequest = new UpdateRequest() { @Override public String getEndpoint() { return "/lights"; } @Override public Map getAttributes() { synchronized (pendingAttr) { Map copy = new HashMap<>(pendingAttr); pendingAttr.clear(); return copy; } }};

Slide 84

Slide 84 text

@MOLSJEROEN 3. REDUCE # REQUESTS private UpdateRequest updateRequest = new UpdateRequest() { @Override public String getEndpoint() { return "/lights"; } @Override public Map getAttributes() { synchronized (pendingAttr) { Map copy = new HashMap<>(pendingAttr); pendingAttr.clear(); return copy; } }};

Slide 85

Slide 85 text

@MOLSJEROEN 3. REDUCE # REQUESTS private class CommunicationStrategy { private Set queue = new LinkedHashSet<>(); public void doRequest(UpdateRequest updateRequest) { queue.add(updateRequest); // logic to trigger requests } }

Slide 86

Slide 86 text

@MOLSJEROEN 3. REDUCE # REQUESTS private class CommunicationStrategy { private Set queue = new LinkedHashSet<>(); public void doRequest(UpdateRequest updateRequest) { queue.add(updateRequest); // logic to trigger requests } }

Slide 87

Slide 87 text

@MOLSJEROEN 3. REDUCE # REQUESTS private class CommunicationStrategy { private Set queue = new LinkedHashSet<>(); public void doRequest(UpdateRequest updateRequest) { queue.add(updateRequest); // logic to trigger requests } }

Slide 88

Slide 88 text

@MOLSJEROEN 4. INSTANT UI

Slide 89

Slide 89 text

@MOLSJEROEN #PROTIP - NEVER ASSUME, ALWAYS MEASURE

Slide 90

Slide 90 text

@MOLSJEROEN CHALLENGES 1. Easy to use (and test) ▸ Wi-Fi setup ▸ Prepare for bad weather 2. Performant ▸ Fast discovery ▸ Maximise control speed 3. Scalable ▸ Lessons learned

Slide 91

Slide 91 text

LESSONS LEARNED PART 3: SCALABLE

Slide 92

Slide 92 text

@MOLSJEROEN DEVELOPING A SYSTEM 0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 1 2 3 4 5 6 7 8 9 10 11 12 New Features Maintenance

Slide 93

Slide 93 text

@MOLSJEROEN DEVELOPING A SYSTEM 0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 1 2 3 4 5 6 7 8 9 10 11 12 New Features Maintenance

Slide 94

Slide 94 text

@MOLSJEROEN DEVELOPING A SYSTEM 0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 1 2 3 4 5 6 7 8 9 10 11 12 New Features Maintenance

Slide 95

Slide 95 text

@MOLSJEROEN DEVELOPING A SYSTEM 0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 1 2 3 4 5 6 7 8 9 10 11 12 New Features Maintenance

Slide 96

Slide 96 text

@MOLSJEROEN DEVELOPING A SYSTEM 0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 1 2 3 4 5 6 7 8 9 10 11 12 New Features Maintenance

Slide 97

Slide 97 text

@MOLSJEROEN DEVELOPING A SYSTEM 0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 1 2 3 4 5 6 7 8 9 10 11 12 New Features Maintenance

Slide 98

Slide 98 text

THE TRUE COST OF SOFTWARE IS IN ITS MAINTENANCE unknown

Slide 99

Slide 99 text

@MOLSJEROEN MAINTENANCE ▸ Big focus on automated testing ▸ Need for good architecture ▸ Over-engineering has a huge cost ▸ Avoid Hype driven development ▸ Think well before introducing new features

Slide 100

Slide 100 text

@MOLSJEROEN #FAILUREHALLOFFAME ▸ Detect working internet connection (Wifi, no internet) ▸ Instrumentation tests ▸ Lock orientation to portrait ▸ Nested fragments ▸ Broadcasts as callbacks ▸ Post( new Runnable(…) ) ▸ Null checks ▸ …. RELATED BLOGPOSTS

Slide 101

Slide 101 text

WRAP UP

Slide 102

Slide 102 text

IN SOFTWARE DESIGN, OFTEN THE CONSEQUENCES OF YOUR DECISIONS DON'T BECOME APPARENT FOR YEARS Kent Beck

Slide 103

Slide 103 text

@MOLSJEROEN CONCLUSION ▸ Developing connected products is hard ▸ Developing systems is even harder ▸ Maximise local connections ▸ Keep things simple for users ▸ Strong focus on automated testing ▸ Proper architecture

Slide 104

Slide 104 text

@MOLSJEROEN IMAGE CREDITS • Welcome image http://www.store.meethue.com/media/catalog/product/cache/1/ feature_img_7/9df78eab33525d08d6e5fb8d27136e95/e/x/expand_your_ecosystem_1.jpg • Wi-fi setup https://images.philips.com/is/image/PhilipsConsumer/AW3000_10-MI1-global-001? $jpglarge$&wid=1250 • Good vs bad weather https://images.philips.com/is/image/PhilipsConsumer/FC8830_82-U1P-global-001? $jpglarge$&wid=1250 • Discovery https://s.blogcdn.com/slideshows/images/slides/403/398/9/S4033989/slug/l/philips-hue-motion- sensor-wall-attached-1.jpg • Control speed http://www.philips.com/consumerfiles/newscenter/main/shared/assets/de/Downloadablefile/ press/elektro_hausgeraete/20140716_Philips_Air_AC4072_11_Lifestyle_4.jpg • Developing a system http://www.philips.com/consumerfiles/newscenter/main/standard/resources/corporate/ press/2014/IFA2014/Saeco-GranBaristo-Avanti_image-5.jpg • Warp up http://www.philips.com/consumerfiles/newscenter/main/standard/resources/corporate/press/2014/ IFA2014/Hue-Beyond-lifestyle_all-three.jpg

Slide 105

Slide 105 text

@MOLSJEROEN MANY THANKS ▸ Jeroen Mols (Belgium) ▸ @MolsJeroen ▸ http://jeroenmols.com/blog