IKEA Vidga Curtain Opener

Overview

This project uses an ESP8266, stepper motor/driver, some belts, sprockets, and pulleys to turn the IKEA Vidga curtain track system into a motorized, home automation controllable curtain opener.
The system uses MQTT in the current incarnation of the code, so you would need an MQTT server already established, but also shouldn’t be hard to adapt to another solution like fauxmoESP. My code and library is included below, but I have not done a clean up pass, and they were built for my particular setup, so expect to need to make changes. If anyone does the work of genericizing please let me know so I can share for others!

BOM

IKEA Vidga triple rail curtain track (rails, wall mounts, sliders, etc) – https://www.ikea.com/us/en/p/vidga-triple-curtain-rail-included-ceiling-fittings-white-70492886/
Wemos D1 Minihttps://amzn.to/3EEKZOZ (May be overkill, but was what I had on hand, and what the 3d printed parts currently require)
NEMA 23 Stepper motorhttps://amzn.to/3ThJYke
Stepper driverhttps://amzn.to/3ECD2Kg
Rotary encoderhttps://amzn.to/3rTc6OT
Power supply 12v 2ahttps://amzn.to/3EFPucf
Idler pulleyshttps://amzn.to/3S0z9C3
60 tooth pulleyhttps://amzn.to/3RZJMEU
GT2 belthttps://amzn.to/3yD62xR
3d printed partshttps://www.printables.com/model/294416-ikea-vidga-curtain-opener

Code

This arduino sketch depends on Encoder, AccelStepper, and my ESPHADevice (below) libraries.

VidgaCurtainOpener.ino

ESPHADevice.h

ESPHADevice.cpp

I need to clean up those libraries to make them more shareable, as they are currently special built for my personal use, but wanted to get this out first.

Advertisement

Dartboard preview

Just a preview of the dartboard project I’ve been working on in my spare time.

I finally got to the stage of the project where I was able to glue the separate pieces together and demonstrate a working example. Now to clean everything up and continue adding games!

Hardware/software breakdown: I’m using a store bought led-lit dartboard, which I have unsoldered from the factory pcb and am using one arduino to drive the led matrix, one arduino to drive the input matrix, a nodejs server running on a raspberry pi to handle game logic, and a react web app front end for the interface, which I have loaded on a fire tablet currently

This is the exact board I used: https://smile.amazon.com/dp/B077PBKL22/

Looks like it’s out of stock on Amazon now but hopefully could find elsewhere with “Viper 42-0003”

I found this one that is ~40% cheaper and in stock. Not identical on the outside but likely an exact match internally, so I would imagine all of the code/circuitry would work plug and play with this board as well: https://smile.amazon.com/dp/B08Y8QKJMD/

Mimo 720-S on the Raspberry Pi

1) Drop the USB speed to v1.1 speeds (necessary for this touchscreen to work unfortunately, although online people have reported theirs working without this step recently)

sudo nano /boot/cmdline.txt

Modify from:

dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait

To: (changes in bold)

dwc_otg.lpm_enable=0 dwc_otg.speed=1 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait

ctrl-x, y, enter to save.

2) Disable the screen saver

sudo nano /etc/lightdm/lightdm.conf

scroll down until you see

[SeatDefaults]
#xserver-command=X

Remove the starting ‘#’ from ‘#xserver-command=X” and add ” -s 0 -dpms” to the end so you have “xserver-command=X -s 0 -dpms” on that line.

ctrl-x, y, enter to save.

3) Create kernel with Displaylink/touchscreen support

Update first:
sudo apt-get update
sudo apt-get upgrade

Install requisites:
sudo apt-get install bc libncurses5-dev

cd ~
mkdir raspbian
cd raspbian
sudo git clone https://github.com/raspberrypi/linux –depth=1
sudo git clone https://github.com/raspberrypi/tools –depth=1
cd linux/
sudo make bcm2709_defcong (bcmrpi_defconfig for rpi v1)
sudo make menuconfig

Navigate to:
Device Drivers>Input Device Support>Touchscreens>USB Touchscreen Driver (hit Y to include. You may need to hit space while on Touchscreens to include the feature and it’s subcomponents – Thanks Richard!)
Hit esc until you’re back at Device Drivers.
Device Drivers>Graphics Support>Frame Buffer Devices>Displaylink USB Framebuffer support (hit Y to include)
Hit esc until prompted to save and select Yes.

Start kernel build:

sudo make -j 6 (takes a looong time)
sudo make -j 6 modules
sudo make modules_install
sudo cp /boot/kernel7.img /boot/kernel7-orig.img
sudo cp arch/arm/boot/Image /boot/kernel7.img
sudo reboot

Now you can run dmesg to make sure the touchscreen shows up properly.

4) Configure X11 to use the new display

sudo nano /etc/X11/xorg.conf

Right click and paste the following in and save:

Section "Device"
Identifier "uga"
driver "fbdev"
Option "fbdev" "/dev/fb1"
Option "ShadowFB" "off"
EndSection

Section “Monitor”
Identifier “monitor”
EndSection

Section “Screen”
Identifier “screen”
Device “uga”
Monitor “monitor”
EndSection

Section “ServerLayout”
Identifier “default”
Screen 0 “screen” 0 0
InputDevice “touchscreen” “CorePointer”
Option “Xinerama” “Off”
EndSection

Section “InputDevice”
Identifier “touchscreen”
Driver “evdev”
Option “Device” “/dev/input/by-id/usb-e2i_Technology__Inc._USB_Touchpanel_L000000000-event-if00”
Option “DeviceName” “touchscreen”
Option “ReportingMode” “Raw”
Option “SendCoreEvents” “On”
Option “Calibrate” “1”
Option “Calibration” “630 32000 1100 31800”
Option “InvertY” “true”
Option “InvertX” “true”
Option “SwapAxes” “false”
EndSection

5) Configure the xorg.conf file with your particular settings

If you’re lucky your display will be named the same as mine and you wont need to make any change. Type:

ls /dev/input/by-id/

and look through the output for the one that is your touchscreen. Now copy that long name and type

sudo nano /etc/X11/xorg.conf

and replace ‘usb-e2i_Technology__Inc._USB_Touchpanel_L000000000-event-if00’ with your display name.

6) Calibrate the screen (if my calibration settings didn’t work for you)

sudo apt-get install evtest
sudo evtest /dev/input/usb-e2i_Technology__Inc._USB_Touchpanel_L000000000-event-if00

again replacing ‘usb-e2i_Technology__Inc._USB_Touchpanel_L000000000-event-if00’ with your display name. Now follow Dane’s post to get the calibration values, and use

sudo nano /etc/X11/xorg.conf

to change the values.

Now if you reboot you should boot up on your mimo display with a working touchscreen!

Enjoy!

Kegerator Flow Meter Test

The first step along the road to getting the kegerator monitor up and running

Flow meter used available from adafruit: http://www.adafruit.com/products/828

Based on the code from: https://github.com/adafruit/Adafruit-Flow-Meter/blob/master/Adafruit_FlowMeter.pde

Source:

#include

#define lcdPin 6

SoftwareSerial LCD = SoftwareSerial(0, lcdPin);
// since the LCD does not send data back to the Arduino, we should only define the txPin
const int LCDdelay = 10; // conservative, 2 actually works

// which pin to use for reading the sensor? can use any pin!
#define FLOWSENSORPINLEFT 2
#define FLOWSENSORPINRIGHT 3

// count how many pulses!
volatile uint16_t pulsesLeft = 0;
volatile uint16_t pulsesRight = 0;

volatile uint16_t lastPulses = 0;

// track the state of the pulse pin
volatile uint8_t lastFlowPinStateLeft;
volatile uint8_t lastFlowPinStateRight;

volatile int32_t lastFlowTimer = 0;

float litersPerTank = 18.9;
float pricePerTank = 78;

bool clearNextTick = true;

// Interrupt is called once a millisecond, looks for any pulses from the sensor!
SIGNAL(TIMER0_COMPA_vect)
{
uint8_t left = digitalRead(FLOWSENSORPINLEFT);
uint8_t right = digitalRead(FLOWSENSORPINRIGHT);

if (left != lastFlowPinStateLeft && left == HIGH) {
//low to high transition!
pulsesLeft++;
}

if (right != lastFlowPinStateRight && right == HIGH) {
//low to high transition!
pulsesRight++;
}

lastFlowPinStateLeft = left;
lastFlowPinStateRight = right;

uint16_t pulses = pulsesLeft = pulsesRight;

if (pulses == lastPulses)
{
if (lastFlowTimer > -1)
lastFlowTimer++;
}
else
{
if (lastPulses == 0)
clearNextTick = true;
lastFlowTimer = 0;
}

lastPulses = pulses;
}

void useInterrupt(boolean v)
{
if (v) {
// Timer0 is already used for millis() - we'll just interrupt somewhere
// in the middle and call the "Compare A" function above
OCR0A = 0xAF;
TIMSK0 |= _BV(OCIE0A);
}
else {
// do not call the interrupt function COMPA anymore
TIMSK0 &= ~_BV(OCIE0A);
}
}

void setup()
{
Serial.begin(9600);
Serial.print("Flow sensor test!");

pinMode(FLOWSENSORPINLEFT, INPUT);
digitalWrite(FLOWSENSORPINLEFT, HIGH);
lastFlowPinStateLeft = digitalRead(FLOWSENSORPINLEFT);

pinMode(FLOWSENSORPINRIGHT, INPUT);
digitalWrite(FLOWSENSORPINRIGHT, HIGH);
lastFlowPinStateRight = digitalRead(FLOWSENSORPINRIGHT);

useInterrupt(true);

pinMode(lcdPin, OUTPUT);
LCD.begin(9600);
clearLCD();
lcdPosition(0, 0);
LCD.print("Starting Up");

lastFlowTimer = -1;
clearNextTick = true;
pulsesLeft = 0;
pulsesRight = 0;
}

void loop() // run over and over again
{
uint16_t pulses = pulsesLeft = pulsesRight;

if (clearNextTick)
clearLCD();
clearNextTick = false;

if (pulses == 0)
{
if (lastPulses > 0)
clearLCD();

lcdPosition(0, 4);
LCD.print("Welcome!");
lcdPosition(1, 1);
LCD.print("Begin pouring!");
}
else
{
float liters = pulses;
liters /= 7.5;
liters /= 60.0;
liters /= 1.4; //weird const

float ounces = liters * 33.8;

float price = liters / litersPerTank * pricePerTank;

if (pulsesRight > 0)
LCD.print("right");
else
LCD.print("left");
lcdPosition(1, 0);
LCD.print("Oz: ");
LCD.print(ounces);
lcdPosition(1, 9);
LCD.print(" $:");
LCD.print(price);

// Reset
if (lastFlowTimer > 1000)
{
lastFlowTimer = -1;
clearNextTick = true;
pulsesLeft = 0;
pulsesRight = 0;
}
}

delay(100);
}

// wbp: goto with row & column
void lcdPosition(int row, int col) {
LCD.write(0xFE); //command flag
LCD.write((col + row * 64 + 128)); //position
delay(LCDdelay);
}
void clearLCD(){
LCD.write(0xFE); //command flag
LCD.write(0x01); //clear command.
delay(LCDdelay);
}

Arduino Powered X10+RFID Controlled Motorized Curtain Opener/Sliding Door Lock

This is a walkthrough of my motorized curtain opener I built using an arduino and some pieces from a robotics kit I had lying around. To controller the curtains or lock I can use X10 (wireless remotes, web interface, iphone app), RFID (cards given to all my roommates) and physical switch to lock it as I leave.

Here’s a little more detailed explanation of the mechanism that opens the curtains:

And here’s a terrible hand drawing laying out the components:
Hand drawing