Create automatic display rotation with MXChip

28th of June 2020 |

6 - 7 minutes

Introduction

Having the display rotate to match the orientation of our device is something we all take for granted on our phones and tablets, but for some reason, it never made it to our PCs even though a lot of content we consume is better suited for a vertical screen (Reddit, Writing, Programming, e.t.c).

This blog post is going to be about how I implemented auto-rotating displays using Microsoft's MXChip IoT DevKit.

Determining the rotation of the MXChip

In order to rotate the display, we first need to know the rotation of the MXChip. To do this we will use the LSM6DSL Sensor, an accelerometer and gyroscope sensor on the MXChip. By rotating the MXChip in my hands and looking at a real-time readout of the accelerometer's X and Y values I was able to find bounds that told me the rotation of the chip.

C++ Copy
int getRotation()
{
sensor->enableAccelerator();
sensor->getXAxes(axes);

// If the X axis is between -500 and 500 the device is vertical
if (axes[0] <= 500 && axes[0] >= -500){
// If the Y axis is >= 0 then the device is pointed down
if (axes[1] >= 0)
return D_DOWN;
// Else the device must be pointing upwards
else
return D_UP;
}
// If we're not vertical we must be horizontal
else{
// If the X axis is >= 0 the device is on its right side
if (axes[0] >= 0)
return D_RIGHT;
// Otherwise its on its left
else
return D_LEFT;
}
}

Now that we know the rotation of the MXChip we need to find a way to send this to the PC so it can rotate the display to match.

MXChip to PC Communication

The MXChip is primarily made for connecting to Azure Web Services, however, I decided not to go with Azure, or any cloud service, for this project. There were a few reasons for this:

  1. This project was made during the 2020 Global Covid-19 pandemic and cloud resources were prioritised for hospitals and other government uses.
  2. I felt that spinning up a database to store the rotation of my monitor might be a little overkill.

My first thought was using a serial connection and this would have worked great apart from I'd have to run a USB cable to the back of the monitor with enough slack to allow it to rotate and well I don't own any USB cables that long. If your monitor has USB passthrough then this would be the way to go.

Since a solution using serial was unfeasible I knew the MXChip to PC communication would have to be wireless. I decided to use MQTT, a publish-subscribe protocol. Using this I could publish all of the sensor data from the chip to the same server but on different topics, therefore allowing future projects to have easy access to the data.

By using MQTT I can publish all the MXChip's sensor data and have easy access to it anywhere. This screenshot is from the MQTT Dashboard app for android.

Implementation

To start with I downloaded and installed an MQTT broker, a server that receives messages from clients and sends them to any clients that are subscribed. I decided to use Eclipse Mosquitto a lightweight command-line broker.

Shell Copy
$ sudo apt-get update
$ sudo apt-get install mosquitto

Once that was set up I wrote a C++ class for the MXChip to handle connecting to the broker, subscribing and receiving messages and sending data to topics. For the PC side I decided to use Python and paho-mqtt to subscribe to the topic where the rotation data was being published and then execute the command to rotate the monitor.

Python Copy
import paho.mqtt.client as mqtt
import os

def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
client.subscribe("monitor/#")

def on_message(client, userdata, msg):
decoded_msg = str(msg.payload, "utf-8")
if ("upright" in decoded_msg):
os.system("xrandr --output eDP --rotate normal")
elif("left" in decoded_msg):
os.system("xrandr --output eDP --rotate left")
elif("right" in decoded_msg):
os.system("xrandr --output eDP --rotate right")
elif("upside down" in decoded_msg):
os.system("xrandr --output eDP --rotate inverted")

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("192.168.0.12", 1883, 60)
client.loop_forever()

I set this script to run at startup and it worked great, the prototype was complete!

Thoughts and future development

This project was definitely a success and is something Ive found myself using almost daily without even thinking about it, that's not to say there isn't improvements I want to make. For one this only works on Linux at the moment, a Windows version would definitely be welcome. Another issue i've ran into is the MXChip losing connection to the Wi-FI, I believe this is an issue of the Wi-Fi signal being rather weak behind my monitor, a way to help mitigate this issue would be setting up a MQTT last will and testament for when the MXChip loses connection, I could then have my phone send me a notification telling me to reset the MXChip. Overall I am very happy with this project and if you have an MXChip or Arduino with an accelerometer handy I would recommend building this project yourself!