2

I am developing a UI that controls various hardware components like lights, appliances, and such. The hardware sends notifications when its state changes. The UI receives a live stream of the state from the hardware. The UI can send commands to the hardware to modify its state (ex: turn a light on/off). It follows a CQRS pattern if you are familiar with that. Sometimes these commands fail for various reasons (loss of connectivity, hardware failure, ...) and there could be a decent amount of latency.

I want to indicate the current state of a hardware component and allow the user to control its state. The following are some possible approaches that I have considered. I'm using turning a light on/off as an example.

  1. UI overrides reported state with expected state till confirmed or a timeout. In this approach a toggle switch indicates the state of the light and controls it. When the switch is toggled from off to on the UI immediately indicates the state as on but the control is disabled till the state change is confirmed by a message from the light. If a message is not received within X seconds then the control is enabled and reverted to its previous known state. The user is then notified that their change didn't work. Any state messages that come in for the light that don't match the expected state are overridden due to the non-deterministic nature of the event stream.
  2. Use stateless controls and display state separately. In this approach an on and off button exist and a label that indicates the current state. The buttons don't indicate state. When pressed they send the associated command (turn the light on or off). The state label doesn't indicate a change till it receives a message from the light. I should probably give feedback to the user on "in-flight" commands. I might should prevent the user from sending a command to change to the state the component is already in.

I need to control states that have options and ranges. I have currently implemented the first option and am using toggles (binary), radio buttons (for more than two modes), and sliders (numeric ranges). It is a bit complex and I feel that it may be confusing for the users when reality doesn't match the UI. For the second option I am unsure about what controls to use and how much it will bloat the UI.

I'm open to alternate approaches. I don't want the user to act off of an inaccurate understanding of the state or be confused by UI state not matching what they see in the hardware.

Should the control indicate the state or should state and control be separated? If state and control should be separated, then what controls should be used for options and ranges and how should they be correlated to the current state? How should feedback be given to the user about "in-flight" commands.

1 Answer 1

2

I'm actually working on a project that faces the exact same challenges you describe. The way I'm handling it is your option 1.

Let's continue using your light switch example: An actual light switch displays the hardware's current state--up for "on", down for "off". Since you're developing a UI to mimic this exact functionality, it makes sense to model the UI after this real-world pattern. However, there's no worry of latency in the real world situation, as it happens instantaneous, and never fails. Thus, as you noted, I think the only problems you need to address are latency and failure.

Latency

Option A:

Latency is an intermediate state. The UI should always provide immediate feedback that the user's click was received, but it's stuck waiting on the hardware's response. Your decision to disable the control while in this limbo period makes perfect sense, and I think communicates the exact right message to the user: "Your message was sent, but we're waiting to hear back". The downside, obviously, is that a user can't "correct" their change until it's been actually applied confirmed by the hardware. The user's response is limited by the speed of the system

Option B:

Alternatively, if you'd not like to disable the element and instead allow the user to toggle as much as they want, change radio button selections, and continue sliding the range selector before hearing a response from the hardware, you could display a small loading spinner next to the corresponding element to indicate that there are outstanding commands. This might be a nice alternative, but special care would need to be taken in development to ensure that the UI always remains in sync after all outstanding commands are resolved.

Failure

A failed state should revert the UI back to what it was. Things get a little more complicated if you go with Latency Option B above, as there could be multiple outstanding commands. Some may fail while others succeed, and that gets a bit hairy to keep everything straight in the UI. Although, one might argue that if a user is clicking everything as fast as they can, they're asking for trouble--nevertheless, at the end of it all, the UI should still reflect the current state of the system.


Not sure if I answered all of your questions--I feel that I'll still find some more along the way.

1
  • Thanks for your feedback! You are right that the issue is how to deal with latency and failure if the control reflects the state. I thought about Option B but like you pointed out it would be complicated. I have been thinking about creating new control variants that could display current and intended state while still approximating standard controls. An example would be a slider that had two bars on it or where the highlight indicates the current state and the handle/marker indicates the desired state. I'm curious if anyone has tried separating control from state and how that worked for them.
    – bygrace
    Jul 13, 2017 at 11:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.