Programming. Electronics. Open-source. Pseudo-random opinions.

python

I recently had the pleasure of building a fairly involved embedded application using a Cypress EZ-BLE module. However, I didn’t have a robust hardware test platform to assist in the process. I did tolerably well using the Cypress BLE Pioneer kit, but the kit has some inherent limitations that prevented thorough testing of all of the project’s features.

First, the BLE Pioneer kit doesn’t expose all of the BLE evaluation module’s pins via accessible headers. Multiple pins are routed to hardware components such as the SW2 user button and RGB LED. This makes it hard to test external signals on these pins, or even to connect a logic analyzer in many cases.

Third, testing a second module required constantly switching debugger connections between two devices, or swapping back and forth between two plug-in evaluation boards. I built a custom breakout board for the second module used for testing, but this too has some limitations. It has no built-in debugger or USB-to-UART bridge, and the design (obviously) doesn’t match exactly with the BLE Pioneer kit. This introduces extra variables into some test results.

In short, it was tedious and inefficient. The BLE Pioneer board is excellent in most respects, but not as a comprehensive hardware test platform for the project I worked on. I don’t think it should change; that would make it less valuable for much more typical use cases. But the fact remains that I need something better going forward.

I’ve never focused heavily on test-driven-development before, and some hiccups in this project revealed just how important it is. Since I have a plenty of future development to do with this same hardware, I have therefore put in some time (hooray for holiday weekends!) to create a platform perfectly suited for automated testing and debugging. I’ve never created this kind of thing before, although I have seen a few lying on coworkers’ desks. This post explains my design choices and how I intend to implement a complete embedded test setup.

Once it’s working as intended, I will make the design available for anyone else who happens to be building with Cypress EZ-BLE modules (which, frankly, are pretty great).

PCB Design

Here’s the “CYBLE-EVAL-TEST V1.0” PCB layout, in all its glory:

The board is not small at 7.5 x 5.5 inches. Given the board’s purpose, I’m not concerned with size—if anything, it needs to be big enough to allow easy physical access to all important signals, sometimes at multiple points. While I normally design for minimum component count and small size, this board uses all through-hole parts, plenty of headers, and off-the-shelf Cypress evaluation kits. My primary goal here is to make all testing possible without using jumper wires or swapping hardware in and out.

The board has a mirrored layout, including two of each of the important pieces. This allows master/slave testing (my requirement), or A/B testing between different designs, or just two identical units operating simultaneously in the same vicinity. Of course, you can also only plug in one set of parts and leave the other sockets empty.

I replicated a few features of the BLE Pioneer kit for convenience, namely the SW1 reset and SW2 user button and the RGB LED. However, I also broke out all of these same signals to header pins and connections to the PSoC 5LP.

Important Components

Here are the Cypress kits required to fully populate the board and use it as intended:

All told, that’s $40 + $20 + $40 + $89 = $189 for all the kits. Other components are negligible in terms of cost.

Another notable feature of the hardware design is the 5-way rotary switch at the bottom, which is connected to four 74HC4066 bilateral analog switch ICs. This selectively connects the MiniProg3’s clock, data, reset, and Vtarg signals to one (or none) of the four programmable kits on the board. Being able to switch quickly and easily between programming targets with a single debugger will be wonderfully convenient.

Aside from the huge collection of headers, the only other components on the board are a few LEDs, buttons, and a 5V to 3.3V regulator.

Headers Everywhere

The image above shows prevalence of standard 0.1″ pitch headers everywhere on the board. Some headers are necessary for plugging in each evaluation board, but the majority of them allow external access or internal connectivity between the PSoC 5LP and BLE module or USB-to-UART bridge and BLE module. I like this approach for the flexibility that it provides, although it means you need 100+ jumpers for a full complement of internal connections. I may opt for DIP switches in a later revision, but I’ll have to think about how that might affect usability after I go through the next round of development.

The various headers provide control over all of the following:

RXD, TXD, RTS, and CTS connectivity between the CYUSBS232 kit and BLE module

In addition—and this is another tremendous convenience—every BLE module pin is broken out to a front-of-board row of labeled pins for simple logic analyzer (or other) connectivity. This solves one of my biggest headaches during the previous development phase. I hate having sprawling jumper wires everywhere going to random analyzer leads. Ugh.

Next Steps

This post is labeled “Part 1” for a reason. I have placed a prototype order for the test PCB, and I’m currently waiting on that; I expect to receive it about 10 days from now. In the meantime, I’ll be working on the firmware/software portions of the test setup. Each of the PSoC 5LP kits will manage GPIO control and monitoring, reporting back to the host PC as directed via a simple binary protocol. The main application logic will reside on the host PC, implemented using Python and PySerial. With all four USB-provided virtual serial ports, the test software will be able to do anything it wants.

Stay tuned for another update after the PCB arrives.

Automated Testing with Cypress EZ-BLE Modules, Part 1 was last modified: March 14th, 2017 by Jeff Rowberg

With our 8-month-old daughter Julia, my wife and I have made liberal use of various types of white noise to help her sleep. Most recently, we’ve employed a spare old Android phone with the White Noise Baby app, a pairing which is honestly pretty darn good at what it does. However, not only is the hardware overkill for what it’s doing, it also has a shortcoming for the type of scheduled and repetitive but also slightly varied usage style we want: namely, there’s no simple way to either automate or remotely control it.

Now, before anyone suggests an Android VNC server or something like DroidMote, note that generic screen-level remote control is not what I was hoping to find. Instead, I wanted something more like a simple phone app or even a home screen widget that I could use to start or stop multiple types of audio with very few taps—you know, the kind of interface you can use at 2 AM without fumbling around for too long.

On top of this, we have a more unique requirement for ultimate convenience: the same device should also allow multiple simultaneous audio streams, each with independent volume control, to combine some kind of background noise with other baby audio (like Winnie the Pooh stories) while still being controllable via the same remote interface. To summarize:

Remote controlled via simple smartphone interface

Multiple audio stream output

Independent audio stream control

User-provided noise type (white, brown, pink, air conditioner, etc.)

User-provided storybook audio library

Good luck finding a device that does all that, especially for anything remotely cheap.

Wait a minute—let’s make one instead! Enter the Raspberry Pi, the answer to so many simple automation challenges like this. It turns out that you can do all of the above with a stock Raspberry Pi device running the standard Raspbian OS, if you’re willing to do a bit of programming (or, if you’re reading this post, copypasting).

There are certainly other options on the app end of things; I may roll my own in the near future as well, but the above two work. (Ignore the few one-star reviews of S-Remote Control. It works perfectly. I think those people must not have known what they were doing.)

For the sake of this post, I will assume that you already have some familiarity with the Raspberry Pi platform and Raspbian operating system, or some functional equivalent. In case you don’t, there are plenty of other resources online to help with that. To continue, you should know how to log into your RasPi system via SSH, and use the shell to run simple commands. You should also know how to edit files directly on the RasPi system; I use the vim editor for this purpose, but nano works fine, as will countless others. Your Pi should also have internet access, since without this, you won’t be able to install the required packages.

Installing Packages

Assuming a stock Raspbian OS installation, you first need to install the mpd and mpc packages, which provide a media player daemon and client. I found these to work well for what I wanted to do, although it is certainly possible that some others exist that would work as well. The main atypical requirement that I have, as noted above, is that the system has to support multiple playback channels simultaneously. The stock omxplayer can easily do one at a time, but not if you want multiple streams with independent volume control.

So, start with the following command:

sudo apt-get install mpd mpc

No other new packages are necessary.

Adding a Second Channel with mpd

A typical mpd installation gives you one server with one output channel. This works fine by itself with no changes to the /etc/mpd.conf configuration file. However, for this project, I need one channel for white noise and another for some kind of music, story books, or anything else that we might want to phase in and out without requiring mutual exclusivity with the white noise. This means creating a new set of configuration and service files for another instance of mpd. This can be done first copying the service and configuration files to new versions of themselves. However, before we do that, there’s one change that must be made to /etc/mpd.conf to allow independent volume control. Open this files in your editor of choice, and add the mixer_type definition to the audio_output { ... } definition section which has type set to alsa:

Setting the mixer type to software results in some increased CPU usage for audio processing, but I couldn’t figure out any simpler way to do it. Leaving the ALSA hardware mixer in place results in both channels using the same volume level.

Once you have done this, copy the configuration file and service definition file to new versions of themselves:

You will see some errors about port 6600 and 6601 binding, but everything will work anyway.

Populating the Media Library

This confused me at first, but it makes sense to me now. The mpd daemon and corresponding mpc client are designed to work together, which means mpc gives you command-line playback control/access to the resources that mpd knows about. You can’t just arbitrarily play any song or load any playlist with a relative (or absolute) path using a call to mpc, which is what I tried to do initially. You can load some songs on demand, particularly streaming internet radio stations, but everything else needs to be loaded into the correct location. For playlists (*.pls), this is /var/lib/mpd/playlists/, and for songs (*.mp3, *.wav, etc.), this is /var/lib/mpd/music. These folders can be modified in the the configuration files found in the /etc folder, but there’s usually no compelling reason to do this.

In my case, I have one MP3 for white noise (Star Trek TNG engine idling, trimmed to 30 minutes), and eight or nine songs. I used Media Player Classic to create one playlist file with the engine noise, and then to create a second playlist with all of the songs on it. MPC is overkill for this job, but it works well enough. You can find some directions on how to make these by hand here or here.

Testing Playback Manually

If you have set up two mpd instances as described above, you can now access them using mpc along with the correct port argument. The default port is 6600, so accessing the first server doesn’t require any specific argument. You should be able to see something like this:

Now, you can try adding a song to the client’s playlist and playing it:

mpc add mysong.mp3
mpc play

…or loading one of the playlists you defined and playing it, for example on the other channel:

mpc -p 6601 load myplaylist.pls
mpc -p 6601 play

You can then change the volume, stop playback, clear the playlist, etc. as desired:

mpc volume 50
mpc stop
mpc clear

Assuming all of this is working (yay!), all we need now is some way to control it remotely.

Creating a Remote Control Listener with Python

Along with the Raspberry Pi platform for the hardware, the Python programming language is fantastic for quick software tools like this. It’s not idea for every situation, of course, but it’s quick and clean and powerful and…well, awesome. Everything you need already comes with the Raspbian OS, so you don’t even have to install anything new.

Create a file called tcplistener.py (or whatever you want) in your favorite editor, and give it the following content:

Now, there are a few things to note about the way this script works. Those of you fluent (or even semi-fluent) in Python can figure this all out pretty easily, and make changes if you want to. The code is pretty self-explanatory, but here is feature list:

Starts a TCP server on power 1234, no specific IP

Does not implement forking and socket selection (no simultaneous clients), but supports a connection backlog of up to 5 clients

Allows sending any of the above commands to the second mpd server by appending “2” to the command, for example:

volumeup2

toggle2

noise2

…

Sends back single 0xAA byte if command accepted, 0xEE byte if command fails

Most of the playback control commands are passed almost directly through to mpc. You can see a list of all the commands that mpc provides by running mpc help from the shell. The way you set up your Python remote script may involve different keywords; that’s up to you.

Once you’ve created the script file and saved it, you have to make it executable and then run it as a background process:

chmod +x ./tcplistener.py
./tcplistener.py &

If you want to kill it later, you can use ps ax to find the PID and kill it with kill {pid}. If this is too cumbersome, you could get fancy and create a service management script for it like /etc/init.d/soundremote or something. Since this was a Q&D set-it-and-forget-it project for me, that seemed like overkill, so I didn’t. Using ps and kill isn’t that hard.

Finally, before geting started with the smartphone app configuration, it is important to make a note of the IP address of the Raspberry Pi device. Ideally, you should configure this to be a static IP, either via appropriate values in /etc/network/interfaces or else by setting up a static DHCP lease on your router for the RasPi’s unique MAC address. In any case, you can get the current IP with ifconfig eth0 (if using wired Ethernet) or ifconfig wlan0 (if using wireless):

Configuring the Remote Control App (Android / S-Control)

Once you’ve installed the S-Remote Control app from the Play Store, start it and do the following:

Tap the round green icon to access the configuration menu

Tap Advanced

Tap Layout and choose the option that you need (probably “6 buttons“)

Tap IP and enter the Raspberry Pi’s IP address that you noted above

Tap Port and enter 1234

Tap back, then tap Keys

For each key you want to define:

Tap Name and enter the value that should be displayed on the button

Tap Data and enter the command to be sent, e.g. “play” or “noise2“

Check the TCP option

Tap back to store the settings

For example, here is the simple setup that I have on my phone:

This app unfortunately doesn’t let you have more than six buttons at the same time, which is somewhat limiting, but it does at least allow something like the above configuration. If I do end up building a custom app to provide more specifically appropriate control of this system, I’ll come back and update this post.

Configuring the Remote Control App (iOS / cmd)

The process here is very similar to S-Remote, though slightly different since cmd allows you to specify multiple targets (a nice feature, though we’ll only need one here). Once you’ve installed the cmd app from the App Store, start it and do the following:

Tap the Settings icon at the bottom right

Tap Manage Destinations

Tap the arrow icon in the top right to add a new destination

Enter a friendly name, the noted IP address, port 1234, and a timeout of 3000 ms

Tap Save to store the new destination

Tap Settings to go back to the main settings area

If desired, enter a suitable screen title (I used “BabySound”)

Tap Manage Control Buttons

For each button you want to define:

Tap the arrow icon in the top right

Tap Add New Command to create a new button

Enter a name to be displayed on the button

Tap ASCII and enter the command to be sent, e.g. “play” or “noise2“

Tap Assign Destination… and select the destination that you defined earlier

Choose a custom button color, if desired

Tap Save to store the new button

Tap Settings to go back to the main settings area

Tap Remote in the bottom icon bar to return to the standard button view

Here is a screenshot of part of the setup that I have on my iPhone:

Again, this isn’t an absolutely perfect app for this specific use case, but it is very good and certainly gets the job done.

Conclusion

That’s it, everyone! With only a Raspberry Pi, speakers, and existing smartphone apps, you can too can have a cheap, capable remote-controlled white noise machine. Or, you can go nuts and customize it even further–put it on a schedule with cron, for instance. I’d love to hear about your own implementations.

InMojo is an excellent sales platform for open-source hardware products. However, it doesn’t have an official API to automate order and customer management. To work around this, I’ve put together a Python script that uses mechanize and BeautifulSoup to scrape order data from the website into a more API-friendly SQLite database. It also updates orders with new statuses, tracking numbers, and tracking URLs.

The InMojo system deals with sales by order number and by item name. The order number is unique, but the item name may repeat. However, present in hidden <input> elements on the sales list pages are unique ID values that are 48-byte alphanumeric strings. These identify both the order itself and the specific product variant ordered, regardless of the item name. This is handy for API-style interaction.

Here’s the syntax help that comes from running the script with no arguments:

inmojo_scrapi.py <command> [arg1 [arg2 [...]]]
initialize fetch complete sale history from InMojo
update fetch status of all sales since last update/init
getsale <sale_num> output JSON-formatted sale record for given sale
getsales [criteria] output JSON-formatted sale/item collection
getsales_csv [criteria] output CSV-formatted sale list
getlines_csv [criteria] output CSV-formatted line item list
CRITERIA:
status=value sales with the given status
user=name sales from the given user
beforeunix=timestamp sales made before <timestamp>
onafterunix=timestamp sales made on or after <timestamp>
beforedate=YYYY-mm-dd sales made before <YYYY-mm-dd>
onafterdate=YYYY-mm-dd sales made on or after <YYYY-mm-dd>
ubeforeunix=timestamp sales updated before <timestamp>
uonafterunix=timestamp sales updated on or after <timestamp>
ubeforedate=YYYY-mm-dd sales updated before <YYYY-mm-dd>
uonafterdate=YYYY-mm-dd sales updated on or after <YYYY-mm-dd>
setstatus <sale_num> <status> [tracking_number tracking_url]

The CSV output is broken apart into separate sale list and line item detail list. Line items include order numbers for correlating data later. Note in the example output below (same as the JSON sale above) that there is one sale with two line items, one of which is a breakout board and the other of which is free shipping:

Note that the item count present in the CSV sale output does not include the shipping line, so the count is actually for the things that were ordered.

“ScrAPI” Limitations

There are certain things that are simply not possible from scraping the website, due to the fact that the information just isn’t there. For example:

There is no shipping address data available

There is no correlated PayPal payment data available

These things are only sent to sellers via email. For some reason, they’re not accessible through the web interface. Also, there are many things that this script could do which it doesn’t, such as:

Getting or setting inventory amounts

Listing, adding, or updating actual items or variants for sale

I did not add support for these things because they fall outside of the category of things that I need to automate (namely, order management).

I might add more features in the future, but I hope the site will incorporate an official API before then. For now, you can take the output of this script and integrate it into other systems such as QuickBooks, Endicia, PayPal, or inventory management tools.

Python InMojo API connector was last modified: March 14th, 2017 by Jeff Rowberg