Introduction: MQTT Bedside Home Control Panel W/ Wireless Charger -alpha

About: I'm a geek! I love learning about and working with all kinds of technologies. I am also a family man. I love spending time with family and friends. There is nothing better than letting the kids run around whil…

For about a year, I've been slowly smartening my home. It is a long story as to why ( and if you're interested, you can read about it here) but I have a very restrictive set of criteria for what I use for home automation. One of which is local control only for critical items - no cloud. That one restriction ensures that I need to build or modify devices to suit my needs. However, some things are just a pain no mater what and there aren't really any commercial solutions for them.

I found that controlling lamps with remote switches such as these is an easy and efficient method of bringing dumb lamps into the smart home fold. However, it introduces a new issue, I don't want to have to pull out my phone every time I want to turn one on or off. Imagine needing to get up in the middle of the night and having to find the phone in the dark, blinding yourself when you turn the screen on, finding the app and the lamp in the app and flipping it on ... all while trying to stay somewhat asleep.

Enter, control panels.

It seems strange to remove local control of a lamp and then having to make something to bring it back. Seems counter productive - and if all you were going to do with it was turn the lamp on and off when you wanted it, that's entirely true. Don't bother adding the wireless control. A lamp works just fine as a lamp.

However, if you want to do more, then one necessary evil in adding the wireless switch is putting back the basic functionality that we all want in a lamp and maybe expanding it in the process. This project is actually one of several projects centered on a central platform that can then be modified based on need to do slightly different things. You can read more about my expanded control panel projects here:

Step 1: What You Will Need

* NOTE: This project is a proof of concept model and as such the enclosure I designed doesn't have all of the mounting holes for bolting in parts nor does it have a finished PCB for the button back-plane. I designed and printed a box for one side of the bed for initial testing.

Once it was pretty clear that I didn't make any critical design errors, I mirrored the design and printed it for the other side. The designs are on my TinkerCad profile as listed below. Please note that this is a early proof of concept and is not the final finished design. It works as is and we've been using them for several months without issue but you're mileage may vary as they say.

* ALSO NOTE:Please, please, please take care with any wireless charging boards and design! They can get pretty warm depending on what they are charging and as such, are a fire risk. Some of the chips on the board listed below can get as hot as 85C. The PLA I used warmed and softened on a first design when charging for several hours. A future release of this project will add a heatsink to some of the components and spacers between the charging circuit and the enclosure. I highly recommend that with this or any other experimental wireless charging design, take great care and monitor the first dozen or more charges with all of the types of devices you use.

For the project as outlined here, you'll need:


Tools / Materials

  • 3D Printer for the enclosure
  • Printer Filament - your choice of color.
    I recommend: PLA or PETG.
    I do NOT recommend ABS due to combustibility.
  • Hot glue gun and glue sticks
  • Wire strippers / cutters
  • Soldering Iron / solder
  • Small Philips screw driver
  • Small needle nose pliers
  • The Code*See Notes in the Code step for alternatives
  • Patience

Step 2: Wiring and Assembly

The Enclosure:
First of all, choose a side to print. These boxes were intended to be set on night stands next to the bed with the buttons and screen facing the bed and not the room. As such, note were the power plug is, that's the "back" of the device. Each side has a box and a bottom cover. The cover is attached to the box with 3 M3 screws and ideally, 4 large rubber feet are added to the bottom so it will not slide around on your table or scratch it.

Additionally, since the box is really light - even fully assembled - I added some groves to the bottom cover so that you could optionally add some lead diver's pellets cemented in place with epoxy. Of course test your fit and make sure that no conductive items make contact with the weights before powering the device.

There are 3 small items that are spacers for different uses

  • A long bar that you'll need two of as a set of stand-offs for the buttons
  • One F shaped stand off to raise the perf board for the NodeMCU.
  • The final U shaped stand-off is to separate the charging board from the coil.
    I used this part in my first box but not in the second - I had enough space to mount the board next to the coil.

*NOTE: I used hot glue to affix all of the components in place but other glues and methods that are non-conductive should be fine as well.

NodeMCU and PCB:

Use the circuit diagram above to wire the control panel. I highly recommend that you wire and test the circuit on a solderless breadboard before permanently soldering the components to the PCB.

There are 8 inputs to the NodeMCU and the pins are connected like the following:

  • A0 (ADC0) - Middle point between the LDR and a 10K Ohm resistor *See Note Below
  • D0 (GPIO16) - Middle point between of a voltage divider that drops the 5V signal from the charging indicator on the wireless charging circuit *See Note Below
  • D1 (GPIO5) - Screen SCL
  • D2 (GPIO4) - Screen SDA
  • D3 (GPIO0) - Button 1
  • D3 (GPIO2) - Button 2
  • D5 (GPIO14) - Button 3
  • D6 (GPIO12) - Button 4
  • D7 (GPIO13) - Button 5
  • D8 (GPIO15) - Not connected
  • SD2 (GPIO9) - Not connected
  • SD3 (GPIO10) - Button 6
  • VIN - +5V Power from USB connector
  • GND - Ground rail on PCB
  • 3V3 - Power rail on PCB

Remove the charging LED on the charging board by heating it up with a solder iron tip and scrape it off making sure not to bridge the to contact points. Then solder a wire to the + side. This will be the input to the processor for charging status.

*NOTE: Measure the voltage from this line with respect to ground. I received a pack of 4 of these and of the two I've built, one outputs 5 volts on that line and the other, 3.3. If the output is 5V, you'll need to use a voltage divider to lower the 5V to 3.3 before connecting it the ESP8266 lest you risk burning out the input and possibly damaging the processor altogether.


I used breadboard style perf board for the main board for simplicity but used standard no-trace perf board for the buttons. I wound up using two by cutting two 30mm x 53mm pieces out of a 70mm x 90mm as I didn't have one that was wide enough. If you can find a 30mm x 115mm perfboard, that would be perfect for this enclosure.

I joined each of the 6 buttons on one side to a common ground bus (a piece of stripped wire soldered to one leg of each button) and then connected that bus line to the ground rail on the PCB. The other side of each button was connected to the NodeMCU as specified above.
I used hot glue to affix the back plane boards to the two risers and those I mounted in the enclosure with hot glue taking care to align the buttons in the holes so that they don't bind when pressed.

*NOTE: Check your spacing of the buttons before you affix them as the holes in the enclosure aren't based on the standard perf board hole placement.


The screen is has 4 connections - power, ground, and two signal lines. I recommend using dupont connectors to connect the screen to the PCB just in case you accidentally swap the SDA and SCL lines during installation. That way the lines can be reversed easily. The power line connects to the 3V power rail on the PCB and the ground line connects to the ground rail.

I attached the screen to the enclosure with the 4 M2 screws and nuts.


The LDR connects to the 3V power rail on one leg and on the other leg, a line goes to the PCB then through a resistor to the ground rail. Between the LDR and 10K Ohm resistor, a signal line will connect to A0 on the NodeMCU. This is the variable signal used to control how bright the backlight is.

Step 3: Code

The code for this project can be found here:

This control panel connects over wifi to your network. From there it uses MQTT for data communication. In my environment, I have a Home Assistant hub and a weather station in my back yard. While I am a fan of Home Assistant, it is not required to use this control panel. any hub or device that can subscribe to MQTT topics and act on them will work including device to device only all you'd need is an MQTT broker somewhere on your network which could easily be hosted by a Raspberry Pi.

My HA hub, among other things, publishes the current day, date, time and am/pm. My weather station publishes many outdoor variables. In its current form the device subscribes to the following topics (change as needed for your environment):

  • environment/time - The current time in 12 hour hh:mm format - received from the HA hub
  • environment/tap - The AM/PM indicator - received from the HA hub
  • weather/temperature - The current temperature outside - received from the weather station
  • weather/raining - The current rain state - Is it raining right now? - received from the weather station

The bedside control panel publishes the state of the inputs including the charging indicator on the following:

  • bedside_cp{#}/button{#}


As I mentioned earlier, this is a proof of concept device and as such very little error checking, commenting, or performance streamlining has been done. Please feel free to add to this code as you like. Also, it may be possible to substitute my code with other firmware options that exist such as tasmota or esphome, though I have not tried it myself.

Use Cases

While I use this device to control some lights in our bedroom, I also built a relay board that connects to our home automation hub to control raising and lowering the bed's headboard (Instructable / Blog Post).

This control panel could be easily modified to display other information, such as home status, information from the internet or nothing at all.

There are still GPIO pins available and so other items could be added such as a buzzer for an alarm clock or notification from your home automation system.

The existing I2C lines used to display information on the screen could also be extended to other I2C devices. Any library that is available for Arduino should work with the NodeMCU and I've made sure to use the standard "hardware" defined I2C pins.

I am currently designing 3 other uses for the core components of this system on other enclosures for other uses. You can read more about that here:

Step 4: Example Integration

The code I wrote uses MQTT to communicate over WiFi and therefore can communicate with any automation hub or device that uses MQTT. I use Home Assistant that has a built in MQTT broker. Below is an example of my HA configuration.

First, you will want to define a set of sensors that listen (subscribe to topics) for state changes published by the control panel:

- platform: mqtt<br>  state_topic: "bedside_cp1/button1"
  name: "Bedside CP1 Button 1"
  icon: mdi:circle
- platform: mqtt
  state_topic: "bedside_cp1/button2"
  name: "Bedside CP1 Button 2"
  icon: mdi:circle
- platform: mqtt
  state_topic: "bedside_cp1/button3"
  name: "Bedside CP1 Button 3"
  icon: mdi:circle
- platform: mqtt
  state_topic: "bedside_cp1/button4"
  name: "Bedside CP1 Button 4"
  icon: mdi:circle
- platform: mqtt
  state_topic: "bedside_cp1/button5"
  name: "Bedside CP1 Button 5"
  icon: mdi:circle
- platform: mqtt
  state_topic: "bedside_cp1/button6"
  name: "Bedside CP1 Button 6"
  icon: mdi:circle
- platform: mqtt
  state_topic: "bedside_cp1/button7"
  name: "Bedside CP1 Charger"
  icon: mdi:circle

Note that the charging status is published as just another button.

With these sensors, you can now do some fun things through the automation tools in HA. For example, you can specify that the first button toggles the state of the lamp right next to it (the point of this project, after all). My lamp uses an inline Sonoff Basic wireless switch. I changed the firmware on the switch to only communicate locally through MQTT and is defined in HA as:

- platform: mqtt<br>  name: "Andys Lamp"
  icon: mdi:lamp
  command_topic: "cmnd/lamp12/power"
  state_topic: "stat/lamp12/POWER"
  availability_topic: "tele/lamp12/LWT"
  payload_available: "Online"
  payload_not_available: "Offline"
  payload_on: "ON"
  payload_off: "OFF"
  qos: 1

Next, we need to use an automation rule to toggle the lamp state when the button is pressed (state from off to on). See pictures above that creates the configuration code below in the automations.yaml file of Home Assistant.

- id: '1547605773820'<br>  alias: MBR Bedside CP Button 1
  - entity_id: sensor.bedside_cp1_button_1
    from: 'Off'
    platform: state
    to: 'On'
  condition: []
  - data:
      entity_id: switch.andys_lamp
    service: switch.toggle

The result is that each time the first button on the control panel is pressed, HA toggles it's state and tells the switch to change to that state.

What if I don't have a hub?

While a hub can make all of this much simpler to manage, it isn't necessarily required. For example, as long as you have a MQTT broker running on your network, the CP state topics can be changed to publish in the format that the lamp switch is subscribed to and a rule can be written in tasmota on the switch to toggle when it sees a message on the topic. It is more complicated but is absolutely possible.

What about that screen?

An example of devices communicating without a hub is the weather data I'm using. I built a weather station (Instructable | Blog Category) that sits out in my back yard. It connects to my network through a wired connection but communicates over MQTT (among other things). Two of the control panel's subscribed topics listen for the rain state and the outside temperature that are published by the weather station. When the weather station sends out that data, it isn't processed by the hub before going to the control panel, it gets displayed directly as it is received.

The time does come from the hub though so we'll need some simple automation that will update the time on the control panel screen. On a one minute interval, the HA hub publishes three topics for date, time and AM/PM. (See the screenshots above that results in the following automation.yaml definition:

- id: '1547348108421'<br>  alias: Publish Date Time
  - minutes: /1
    platform: time_pattern
    seconds: '0'
  condition: []
  - data:
      payload_template: '{{now().strftime("%I:%M")}}'
      topic: environment/time
    service: mqtt.publish
  - data:
      payload_template: '{{now().strftime("%p")}}'
      topic: environment/tap
    service: mqtt.publish
  - data:
      payload_template: '{{now().strftime("%B %d, %Y")}}'
      topic: environment/date
    service: mqtt.publish

The Home Assistant interface still has a lamp switch for my lamp but in addition to my being able to control the lamp with my phone, I can reach over and press the first button. Additionally, my home automation system also controls the lamp automatically through a set of rules for Home/Away state, time of day automation and security and safety rules.

Step 5: Resources

If you're new to MQTT and using it with the Arduino IDE (via netduino, NodeMCU, etc), please see below for more information:

As for using it with the Arduino IDE, see these:

Arduino Contest 2019

Participated in the
Arduino Contest 2019