Welcome to dev/blesi!


This is where I collect my thoughts on everything technology. Below you'll find a collection of my most recent blog posts. For a full list of blog posts, visit the section of my site. For information on a number of my technical projects visit my section. And for more information about me, check out my section.

Enjoy!

-- Patrick Blesi

I recently created a number of wifi touch lights to help my family keep in “touch” with each other. It was a fun project, but there was a bit of a challenge getting everyone’s light set up. I was giving the lights as gifts, and I did not want my family members (some of them not as tech savvy) to have to go through the Photon wifi setup using a web application or mobile app.

Luckily, Particle’s API provides a way to set wifi credentials for your Photon from within the source code of the flashed program. They provide great documentation describing this API, however they don’t provide any tutorials for the steps necessary to set wifi credentials from within your code. Below I describe how to set up wifi credentials manually for your Particle Photon.

The first step is to place your photon in SEMI_AUTOMATIC mode. This must be done outside of the setup and loop functions.

SYSTEM_MODE(SEMI_AUTOMATIC);

setup() {
  // Setup code goes here
}

void loop() {
  // Do more stuff here
}

SEMI_AUTOMATIC mode does not immediately connect to the particle cloud, but waits until you manually call Particle.connect() to connect to the cloud. Once connected to the cloud, your particle automatically manages the connection.

Once your Photon is put into SEMI_AUTOMATIC mode, you can manually set up your wifi connection at the beginning of your setup function. You can specify up to five sets of credentials for Photons and seven sets of credentials for Cores. If more credentials are specified, the oldest credentials will be overwritten.

SYSTEM_MODE(SEMI_AUTOMATIC);

void setup() {
  WiFi.on();
  WiFi.disconnect();
  WiFi.clearCredentials();
  WiFi.setCredentials("SSID", "password", WPA2, WLAN_CIPHER_AES);
  WiFi.setCredentials("ALTERNATE_SSID", "other_password", WPA2, WLAN_CIPHER_AES);
  WiFi.connect();
  waitUntil(WiFi.ready);
  Particle.connect();

  // Rest of setup code goes here
}

void loop() {
  // Do more stuff here
}

You can find more details on setCredentials in the Particle Reference Docs. The first argument is the name of the wifi access point/router. The second argument is the password to connect to the wifi access point. Both the third and fourth arguments are required if the access point is not accessible when the credentials are set.

The third argument specifies the authentication procedure. It must be one of WPA2, WPA, or WEP. WPA2 is the most modern and secure authentication procedure, and WEP is the oldest. The fourth argument specifies the security cipher. Possible security cipher options are WLAN_CIPHER_AES, WLAN_CIPHER_TKIP, and WLAN_CIPHER_AES_TKIP. Of these WLAN_CIPHER_AES is the most modern and secure, and WLAN_CIPHER_TKIP is the oldest. WLAN_CIPHER_AES_TKIP is a mixed mode cipher configuration.

This gives you a working solution, but you can clean this code up a bit by placing the wifi setup code in its own function:

SYSTEM_MODE(SEMI_AUTOMATIC);

setup() {
  setupWifi();

  // Rest of setup code goes here
}

void loop() {
  // Do more stuff here
}

void setupWifi() {
  WiFi.on();
  WiFi.disconnect();
  WiFi.clearCredentials();
  WiFi.setCredentials("SSID", "password", WPA2, WLAN_CIPHER_AES);
  WiFi.setCredentials("ALTERNATE_SSID", "other_password", WPA2, WLAN_CIPHER_AES);
  WiFi.connect();
  waitUntil(WiFi.ready);
  Particle.connect();
}

This is a pretty good solution, but if you commit your code to a source code management system like Git (which you should), then this makes it hard to commit your code without commiting your wifi credentials. This can be remedied by placing our credentials in a separate file:

/*
 * src/wifi_creds.h
 */

// See https://docs.particle.io/reference/firmware/photon/#setcredentials- for details
struct credentials { char *ssid; char *password; int authType; int cipher; };

const credentials wifiCreds[] = {
  // Set wifi creds here (last entry will be tried first when connecting)
  // {.ssid="SSID", .password="password", .authType=WPA2, .cipher=WLAN_CIPHER_AES}
};
/*
 * src/main.ino
 */

#include "wifi_creds.h"

SYSTEM_MODE(SEMI_AUTOMATIC);

setup() {
  setupWifi();

  // Rest of setup code goes here
}

void loop() {
  // Do more stuff here
}

void setupWifi() {
  WiFi.on();
  WiFi.disconnect();
  WiFi.clearCredentials();
  int numWifiCreds = sizeof(wifiCreds) / sizeof(*wifiCreds);
  for (int i = 0; i < numWifiCreds; i++) {
    credentials creds = wifiCreds[i];
    WiFi.setCredentials(creds.ssid, creds.password, creds.authType, creds.cipher);
  }
  WiFi.connect();
  waitUntil(WiFi.ready);
  Particle.connect();
}

You can commit src/wifi_creds.h to be used as a template, and then not commit this file when you have added credentials to the wifiCreds array.

What if you want to flash firmware onto your Photon, but don’t want to overwrite the wifi credentials currently on your Photon? You can make one more tweak to your code to allow for updating the Photon’s firmware without manually specifying wifi credentials:

/*
 * src/wifi_creds.h
 */

// Uncomment the line below if specifying credentials in this file
// #define WIFI_CREDENTIALS_SPECIFIED

// See https://docs.particle.io/reference/firmware/photon/#setcredentials- for details
struct credentials { char *ssid; char *password; int authType; int cipher; };

const credentials wifiCreds[] = {
  // Set wifi creds here (last entry will be tried first when connecting)
  // {.ssid="SSID", .password="password", .authType=WPA2, .cipher=WLAN_CIPHER_AES}
};
/*
 * src/main.ino
 */

#include "wifi_creds.h"

#ifdef WIFI_CREDENTIALS_SPECIFIED
SYSTEM_MODE(SEMI_AUTOMATIC);
#endif

setup() {
#ifdef WIFI_CREDENTIALS_SPECIFIED
  setupWifi();
#endif

  // Rest of setup code goes here
}

void loop() {
  // Do more stuff here
}

void setupWifi() {
  WiFi.on();
  WiFi.disconnect();
  WiFi.clearCredentials();
  int numWifiCreds = sizeof(wifiCreds) / sizeof(*wifiCreds);
  for (int i = 0; i < numWifiCreds; i++) {
    credentials creds = wifiCreds[i];
    WiFi.setCredentials(creds.ssid, creds.password, creds.authType, creds.cipher);
  }
  WiFi.connect();
  waitUntil(WiFi.ready);
  Particle.connect();
}

By commenting or uncommenting #define WIFI_CREDENTIALS_SPECIFIED you can control if code-specified credentials are placed on the Photon.

Setting up particle projects in this way will give you the flexibility to set your Photon’s wifi credentials manually, without having to use additional tools such as Particle’s mobile or web applications.

Cheers!



This fall a recent death in the family left a bit of a gap in our life. My wife started searching for a way for our family to better keep in contact with each other. After some searching, she came across these long distance touch lamps. Intrigued by the concept, I searched to see if I could build a similar product at a more appealing price point.

Wifi Touch Lamps

After some searching, I discovered the kickstarter project of the same lamps found on Uncommon Goods and the creator’s step-by-step how-to on Instructables explaining how he made the Filimin touch lamp. What follows is my own how-to on how I created wifi enabled touch lamps to connect my wife, her mom, grandma, and aunt.

The wifi lamps change color when touched and synchronize their colors to be the same no matter where in the world they are located. Each lamp gets assigned a default color so you know who has touched their lamp. This implementation is adapted and heavily borrowed from John Harrison’s original touch lights.

Materials, Supplies, And Tools

Below are the materials, supplies, and tools I used to make my touch lamps.

Materials

Supplies

  • Wire (18 gauge)
  • Solder
  • Hot Glue
  • Goo Gone to remove sticky adhesive from the bottom of the lamp

Tools

  • Screwdriver
  • Razorblade
  • Soldering iron
  • Hot glue gun
  • Drill and 3/32” drill bit
  • Wirecutter/wire stripper

Step 1: Disassemble the Unifun Touch Lamp

The first step is to disassemble your Unifun Touch Lamp. The finished product should look like the following.

Unifun Touch Lamp packaging Disassembled wifi touch lamps

  1. Remove the foam ring from the bottom of the touch lamp. Be careful to remove as much of the stickiness as possible from the bottom of the lamp.
  2. Unscrew the screws from the bottom of the lamp and remove the bottom plate.
  3. Remove the four silver screws to loosen the top white dome from the base of the lamp. Do not remove the dome yet.

    Unifun Touch Lamp packaging Unifun Touch Lamp contents Foam base ring on Unifun Touch Lamp

    Sticky residue under foam ring Silver screws connecting white dome to the lamp base Loosened white dome

  4. Peer between the white dome and the base for a thin wire connecting the top touch plate to the circuitboard. Cut this wire with a razorblade or wire cutter.
  5. Unscrew and remove the circuit board from the lamp base.
  6. Use a screwdriver to push the flaps holding the touch plate to the white dome.
  7. Use a soldering iron to remove the wire connected to the touch plate.

    Unifun lamp circuit board Inside of lamp white dome Disassembled Unifun Touch Lamp

Step 2: Prepare the Shell

Once you have your lamp disassembled, you need to prepare it to be reassembled with your wifi-enabled components.

  1. Use Goo Gone or some other solvent to remove the sticky residue off of the bottom plate of the lamp.
  2. Use a 3/32” drill bit to drill a whole through the center of the battery compartment of the white dome.
  3. Cut a 6-3/4” piece of wire and solder it to the touch plate.

Hole drilled in white dome Wire soldered to touch plate

Step 3: Connect the Electrical Components

Now it’s time to connect the electrical components together.

  1. Solder a 3-3/4” wire to each of the VIN, GND, and D2 pins of the Particle Photon.
  2. Solder the 10M-Ohm resistor to pins D3 and D4 of the Photon.

    Touch lamp electrical components Photon with components soldered on

  3. Thread the wires through the holes in the base and solder them to the NeoPixel. VIN should connect to “PWR +5V”, GND should connect to “GND”, and D2 should connect to “Data Input”. There may be multiple power and ground pins, choose the ones that are closest to the wires. It is helpful to plug a USB cable (unpowered) into the photon through the USB hole in the lamp base to help hold the Photon in place.

    Wires thread through lamp base NeoPixel soldered to the Photon

Step 4: Test the Lamp’s Functionality

At this point we are ready to test the Lamp’s functionality to ensure we soldered everything correctly and all the components are working.

If you have not yet set up your Photon, plug it in and use the app provided by Particle to connect to your Photon and get it connected to the internet via wifi. Particle provides good instructions for getting your Photon connected.

Once you have your photon connected, you should set up your development environment for getting code onto the Photon, I prefer using their command line tool, but their web IDE is pretty nice as well if you want to get started quickly.

If you are using the command line tool, then you can clone the repository containing the code from Github in order to flash it onto the Photon, otherwise you will need to copy and paste the code into the web browser in order to use it. I will assume you are doing the former.

  1. Once you have connected your Photon to the internet, installed the command line tool, and logged in, you can clone the touch_light repo by running:

     $ git clone git@github.com:pblesi/touch_light.git
    
  2. In src/touch_light.ino update NUM_PARTICLES with the number of touch lamps you intend to have linked together.
  3. Update particleId[] with the 24 character unique identifier for your Photon. This can be found by running particle list on the command line.
  4. Update particleColors[] with your prefered default color for this lamp. Some trial and error may be required to identify which color corresponds to which number. Each color is a value between 0 and 255 that maps onto the RGB Color wheel. 0 and 255 correspond to green.
  5. Compile your code into a firmware .bin file.

     $ particle compile photon
    
  6. Flash your photon

     $ particle flash <the name of your touch lamp> <the generated firmware.bin file>
    
  7. You should see a white flash, a cycle through the color wheel, and then a fade out on green. If you do not see this behavior, check for a short in the circuits. You should not touch the lamp between when the light flashes and when it traverses the color wheel as it is calibrating its touch sensor.

Step 5: Secure the Components

Once you have verified the lamp lights up as expected, you can secure the electrical components to the lamp fixture.

  1. Apply four dollops of hot glue to the lamp base in order to secure the NeoPixel. Do this quickly to prevent having the glue prematurely dry without securing the NeoPixel.
  2. Secure the wooden dowel to the lamp base (I used a pencil) behind the Photon board. This is used to prevent the Photon from moving when a USB cable is plugged into it. When gluing the wooden dowel, be careful to not cover the three holes that are used to secure the white dome to the lamp base (the fourth hole will be covered by the Photon).
  3. Unplug the USB cable from the Photon and check if it comes loose. If the Photon comes loose, secure it by gluing it to the base. If you cannot remove the Photon, put glue around the edges to make sure it stays in place. As soon as the Photon is put in place, make sure the Photon is aligned with the USB hole and plug the USB cable into the Photon to ensure it fits easily when the Photon is secured.

    NeoPixel glued to the lamp base Wooden dowel glued to secure the Photon Photon glued to the lamp base

Step 6: Reassemble the Lamp

You’re almost finished! All that’s left is to connect the touch plate to the Photon and reassemble the lamp.

  1. Screw the white dome back into the lamp base.
  2. Reattach the touch plate to the white dome, threading the attached wire through the hole drilled in the battery compartment.
  3. Solder the wire from the touch plate to the D3 side of the resistor.
  4. Screw the bottom plate back on to the base.
  5. Place six felt pads along the bottom ring of the lamp, covering the exposed screw holes.
  6. You’re done! You can now play with your wifi touch lamp!

    Touch plate soldered to the Photon Exposed screw holes on the touch lamp Felt pads covering the screw holes

Final Product

I built four lamps to give to my wife, her mother, grandma, and aunt. They work beautifully and were a joy to build. As a first Photon project, they were easy to get started and assemble. Check out the video below for a demonstration of how they work.



Recently, frustrated with my inability to solve a wooden puzzle at my in-laws, I realized a computer is much better suited to solve a wooden puzzle than I am. So I decided to put the years I spent studying computer science to use, writing a solver for this puzzle using a depth-first search algorithm. Meanwhile, while the computer works for me, I can sit in the sun and sip lemonade!


The DominoPeg Puzzle 


The DominoPeg puzzle is a 12-piece wooden puzzle where each piece is surrounded by circles or absences of circles. There are six of these spots on each piece, one on each corner and one on each of the long sides. Pieces can be placed in the puzzle vertically or horizontally; they can be flipped over as well to fit into the puzzle. When all pieces are fit into the puzzle, five holes will be present.

It is difficult to fit all the pieces into the puzzle, and it is even more difficult to find a solution to the puzzle given a specific arrangement of these five holes. This is what prompted me to write a solver.



A wooden dominopeg puzzle with holes arranged in a diagonal pattern



The Solver

The entire solution can be found here.

I wrote the solver in Ruby for the same reason that I write so many of my solutions in Ruby: because it's fun! The solution is 249 lines long. It consists of a Piece class, a Board class, and a Solver module. We'll set up a domain to represent our puzzle and then employ a depth-first search algorithm to find a solution to the puzzle. 


Setting the Problem Domain


We represent the puzzle board by setting up a grid. The puzzle actually contains two grids, one that represents the placement of the pieces, and one that represents the locations of the circles, leaving 5 circles empty when all puzzle pieces are placed in the puzzle. The board's piece dimensions are 6 x 4 and its circle dimensions are 7 x 5. Each puzzle piece has piece dimensions of 2 x 1 and circle dimensions of 3 x 2. When placing a puzzle piece on the board we keep track of both the piece positions that the puzzle piece takes up and the circle positions that the puzzle piece takes up.

The board is represented by a circle grid where each circle is represented by index 0 through 34

The board is also represented by a piece grid where each piece location is represented by index 0 through 23

When the board is organized in this way, placing a piece on the board is a matter of marking what spots the piece takes up, and continuing to place pieces on the board until we find a solution. 


We represent puzzle pieces based on the circles that they cover. We have canonical representations of each of the 12 puzzle pieces. In addition to these 12 canonical representations, we represent flipped puzzle pieces and rotated puzzle pieces as separate puzzle pieces that are variations of the same canonical puzzle piece. These transformations of puzzle pieces lead to 70 distinct puzzle pieces when orientation is taken into account. The reason there are 70 distinct pieces and not 96 (12 pieces X 4 rotations X 2 flips) is because some of the pieces contain symmetry and are duplicates of each other.

def _init_pieces
pieces = []
BasePieces.each do |base_piece|
Flips.each do |flip|
Orientations.each do |orientation|
pieces << Piece.new(base_piece, flip, orientation)
end
end
end
pieces.uniq { |piece| [piece.transpose, piece.horizontal?] }
end

BasePieces = [
{id: "0", spots: [0, 1]},
{id: "1", spots: [0, 2]},
{id: "2", spots: [0, 7]},
{id: "3", spots: [0, 8]},
{id: "4", spots: [0, 9]},
{id: "5", spots: [1, 8]},
{id: "6", spots: [0, 1, 2]},
{id: "7", spots: [0, 1, 7]},
{id: "8", spots: [0, 1, 8]},
{id: "9", spots: [0, 1, 9]},
{id: "A", spots: [0, 2, 7]},
{id: "B", spots: [0, 2, 8]},
]

Flips = [false, true]

Orientations = [0, 90, 180, 270]

Flips represent whether the piece is a flipped version of one of the canonical representations. Orientation represents whether the canonical pieces is rotated and by how many degrees it is rotated (0 representing no rotation of the canonical piece). A base piece's spots represent the circles that would be covered on the board if the piece were to be placed in the top left of the board. 

In order to represent each piece we take the canonical representation and apply transformations to the piece positions and circles that it covers. 

def piece_positions
horizontal? ? [0, 1] : [0, 6]
end

def transpose
return @transpose if @transpose
spots = base_piece[:spots]
spots = spots.map { |spot| FlipMap[spot] } if flip
@transpose = spots.map { |spot| OrientationMaps[orientation][spot] }.sort
end

FlipMap = {0=>7, 1=>8, 2=>9, 7=>0, 8=>1, 9=>2}

OrientationMaps = {
0 => {0=>0, 1=>1, 2=>2, 7=>7, 8=>8, 9=>9},
90 => {0=>1, 1=>8, 2=>15, 7=>0, 8=>7, 9=>14},
180 => {0=>9, 1=>8, 2=>7, 7=>2, 8=>1, 9=>0},
270 => {0=>14, 1=>7, 2=>0, 7=>15, 8=>8, 9=>1},
}


Solving Using Depth-First Search


The solver is a recursive algorithm employing depth-first search. For each of the puzzle pieces it has, it places the piece in the puzzle, and then tries to solve a new puzzle with the new set of puzzle pieces (the placed puzzle piece and canonical equivalent pieces are removed) and the new board (because the new board has additional constraints added to it by the piece that was just laid).

If there are no more puzzle pieces left then we know that we have placed all the puzzle pieces on the board and have found a solution. If we go through all our pieces and none of them can be placed on the board, then we know we've hit a dead end and this board cannot be solved with this set of puzzle pieces.

module Solver
def self.solve(board, pieces)
if pieces.any?
pieces.each do |piece|
if board.accepts?(piece)
new_pieces = remove(pieces, piece)
new_board = Board.from_existing_board(board)
new_board.apply(piece)
solution = solve(new_board, new_pieces)
return solution if solution
end
end
else
return board
end
nil
end

def self.remove(pieces, piece_to_remove)
pieces.reject do |piece|
piece.base_piece[:id] == piece_to_remove.base_piece[:id]
end
end
end

When determining if a board accepts a piece, we only need to look at the top left most uncovered piece position. If we cannot fit any of our pieces into that position, then the current board configuration is invalid and there is no need to try to further fit pieces into this configuration.

def accepts?(piece)
first_piece_spot = _first_empty_piece_spot
piece_positions = _piece_positions(first_piece_spot, piece)

if piece_positions[0] % PIECE_WIDTH + piece.piece_width > PIECE_WIDTH
return false
end

piece_positions.each do |piece_position|
return false if piece_position >= PIECE_WIDTH * PIECE_HEIGHT
return false unless piece_board[piece_position].nil?
end

first_circle_spot = _piece_spot_to_circle_spot(first_piece_spot)
_circle_positions(first_circle_spot, piece).each do |spot|
return false unless board[spot].nil?
end

true
end

When verifying that a piece fits on a board, we first perform a check to see if the piece position goes off the edge of the board horizontally. Then we check both the piece positions and the circle positions to make sure that they both fit on the board.

When checking the piece positions, we verify that the piece does not go off the board vertically and that there are no other pieces that would be in the way of this piece before we place it.

Finally, we check all the circle positions that this piece would fill on the board and verify that no previous pieces are filling these circle positions. If all of these checks pass then this piece can validly be placed on this board.


Putting It All Together


Now that we have our domain and our solver, we can put them together to solve our puzzle.

def main
pieces = _init_pieces
board = Board.new([0, 7, 14, 21, 28])
solution = Solver.solve(board, pieces)
puts solution
end

main if __FILE__ == $PROGRAM_NAME

Main is the main jumping point into our program. We initialize all of our distinct pieces, set up a board passing in a list of constraints that represent the 5 circles we want to be blank at the end, invoke solve on our board and pieces, and then print the solution.


The Results


Because this is a depth-first search solution, solution times will vary depending on where the solution is located in your search space and how you choose to traverse that space. Solving three puzzles with different constraints produced the following results:

Puzzle ConstraintsTime to SolveTotal Pieces Placed
Board.new([0, 10, 20, 24, 28])5m15.509s4,461,278
Board.new([0, 7, 14, 21, 28])2m49.996s2,397,106
Board.new([25, 26, 27, 32, 33, 34]) (Unsolvable)24 hours+1,220,171,512


The puzzle with unsolvable constraints gives you an idea of size of the search space of this problem. I stopped the solver after 24 hours. Though it is difficult to adequately determine the total number possible placements of pieces due to the complexity of the constraints, my rough calculations indicate that to try all possible combinations of laying pieces on the board would take years given this solver.

These results were derived on my laptop with a core i7 processor, running single-threaded (because this is Ruby).

A lot of improvements could be made to the performance of this algorithm. This approach is fairly naive and leaves out a lot of optimizations for the sake of readability. For example, a faster algorithm would take advantage of constraints as soon as possible, so it would be more optimal to find the provided constraints and place pieces around them, failing faster than trying possibilities that do not take advantage of these constraints.

Also, choosing a more performant language and one that can utilize native threads to parallelize the search for a solution would provide an additional speedup that we are not able to leverage with Ruby.

Thanks for reading! Have any thoughts on solving this puzzle or solving any other puzzles using artificial intelligence? Leave a comment below.