Sunday, August 11, 2013

Control Your Projector From Your Computer With Pyjector

I recently bought my first projector, a BenQ w1070. It has an RS-232c port, a type of serial connector.  This serial port allows you to send commands to the projector, controlling everything from brightness to the current source.  Of course, you have to do some work to do anything useful...

The first step is to get a suitable cable. You will likely end up with something like this, a USB to serial adapter. It uses a Prolific chipset, which has a driver included in the Linux kernel - which will save you the headache of trying to get your adapter working, if you are on Linux.  That adapter has a female connector, and most projectors seem to also have female connectors, so you will also need a null modem adapter (a few bucks on Amazon or locally).  If both connectors are the same gender, be sure to get the right adapter - you most likely want a null modem adapter, not just a "gender changer".  You can check the pin-out for your specific device to be sure.

After plugging in the serial adapter, be sure that it is correctly detected by your OS (in my case, Linux). A quick search through the syslog with dmesg | grep Prolific  will show if it was detected. You can then check that you have proper communication between your PC and the projector by using a program called minicom. On my Debian system, I used aptitude install minicom to grab this program. There's a decent tutorial here that will guide you through setting up minicom. I'd use it only to verify you can communicate with your projector - it's not the most convenient program to use.

Now comes the good part, using Python to tell your projector what to do. I created a library called Pyjector to make this easier. You can install it with pip install pyjector. It has two points of interest - the library itself, and a script shipped with it called pyjector_controller.

The pyjector_controller script should be used if you plan to control your projector from the command line. It accepts 4 arguments - device_id, port, command, and action. The device id is used to look up what commands your projector supports, and how to send them. At the moment, "benq" is the only supported device id, which should work for all BenQ models. The "port" is the port your projector is connected to - if you previously used minicom, you should already have this information. The command is... the command you want to run, such as "power" or "mute". The action is a verb like "on" or "off".
Putting it all together, here's a command to turn on the projector:
./pyjector_controller benq "/dev/ttyUSB0" power on

You can also use the Pyjector library in your own Python scripts. Just instantiate it like so:
pyjector = Pyjector(port=port, device_id=device_id)
Pyjector will read the config for the device you specify, and automatically create command methods on itself, so now you can do pyjector.command(action). In practice, that will look like:
pyjector.power('on')
You can check what commands are supported with:
print(pyjector.command_list)
and you can check the available actions for a specific command with:
print(pyjector.get_actions_for_command('')
If Pyjector doesn't have the functionality you need, you can also access the underlying PySerial instance:
pyjector.serial.write('some other command here')
On the subject of PySerial, defaults for the device you specify are used to connect to your projector, such as baud rate, parity bits, etc. Your projector might be slightly different, so you can override the defaults when instantiating the Pyjector object. Simply use keyword arguments to provide any options to PySerial (you can see the PySerial docs for details). For example, if your projector uses 115200 baud rate instead of whatever the config uses, you can do:
pyjector = Pyjector(port=port, device_id=device_id, baud_rate=115200)
This should allow you to create scripts to control your projector as you wish. If you have a projector that doesn't have a config in Pyjector, the format is simple enough that you can create your own. There are some instructions in the README for doing so. Please make a pull request if you do, so it can be used by others. Enjoy.

Sunday, January 6, 2013

Getting A Job: Observations From A College Senior

I have six months of college left, and signed an offer letter over a month ago. Now seems to be a good time to share some observations I've made in regards to getting your first "real" job. Hopefully it'll help those that come after me.

From what I've seen, the people who are doing the best in their job searches fall into two broad categories: those with great academics (strong GPAs, solid understanding of CS principles), and those with great experience. It seems that very few fall into both categories - if you are always working at your job, or on side projects, your GPA is inevitably going to suffer to some degree.

The people with strong GPAs have their resumes peculate to the top of the pile, and tend to do reasonably well at most interviews. From what I've seen and experienced, most of the "just out of college" interviews focus on solving programming brain teasers, a la Google. With a little bit of practice, they aren't hard to beat - you don't necessarily need to solve the problems, only to walk the interviewer through a concise and thoughtful set of possible (and iteratively better) solutions. Many of the students in this position have gotten job offers from big names like Amazon and Microsoft.

The other group of people, the group that I think I fall into, doesn't have a 3.95+ GPA. Of course, they still have reasonable GPAs. What this group lacks in pure GPA, they make up for in experience. There's multiple kinds of experience - actual job experience, and side project experience.

At Drexel, with mandatory co-ops (internships) during your schooling, everyone has some job experience. Those that stand out either have impressive projects, worked at impressive places, or worked all through school. Companies love to see a GitHub account full of cool projects (they will look!), and I can't express enough how important it is to have real field experience coming out of college. From what I've seen, it gives you a huge advantage over those without.

The downside of internships is that a surprising amount of students chose not to treat them like a job. On the other hand, working hard during your internship can have great rewards. Not only are you going to learn a ton of practical knowledge, but oftentimes a full-time job can result.

My family and friends often say "you're so lucky" when I speak to them about my upcoming job, but that's not the reality. I went into my internship with the attitude that I could turn it into a full-time position if I worked hard enough. It worked, and I landed an awesome job. My fiance (currently getting her masters in Library Science (!)), took the same attitude, and got the same results.

Assuming you fall into one of the two above groups - start your job search early. I was amazed at how early recruiters swooped in. Don't take the first job that comes your way. Here in Philadelphia, with a rather small tech sector, computer science majors, out of all the majors, are reputed to have the best job prospects. Use that to your advantage - get multiple offers, and negotiate as best you can.

As my graduating class has 6 months of school left, I'm not sure what will happen to the kids without either a great GPA or any experience besides ho-hum internships. I do know that while myself and my friends either already have jobs lined up, or have recruiters lined up to see us, they are blindly strolling along, just trying to finish up classes; not thinking of their future. It will be interesting to see how they make out.

Tuesday, January 1, 2013

Extract From Remote Host With KDE Context Menu

I oftentimes want to extract files from a rar or zip archive, and use KDE's provided context menus to do so (right click > extract archive here).  This method falls short when files are on a network drive, as the data is round-tripped to my local machine and back to the remote host, which slows the operation greatly on my home 100mbit network.

To fix the issue, I made a simple context menu item, saved to /usr/share/kde4/services/ServiceMenus/remote_extract.desktop

[Desktop Entry]
Type=Service
ServiceTypes=KonqPopupMenu/Plugin
MimeType=application/x-tar;application/x-compressed-tar;
application/x-bzip-compressed-tar;application/x-tarz;
application/x-xz-compressed-tar;application/x-lzma-compressed-tar;
application/x-deb;application/x-cd-image;application/x-bcpio;
application/x-cpio;application/x-cpio-compressed;application/x-sv4cpio;
application/x-sv4crc;application/x-rpm;application/x-servicepack;
application/x-rar;application/x-7z-compressed;application/x-java-archive;
application/zip;application/x-compress;application/x-gzip;application
/x-bzip;application/x-bzip2;application/x-lzma;application/x-xz;
application/lha;application/x-lha;application/maclha;
Actions=extractRemote

[Desktop Action extractRemote]
Name=Extract Archive on Host
Icon=utilities-file-archiver
Exec=ssh user@host 'cd `dirname %f`;ark --batch --autodestination --autosubfolder "%f"'

The above assumes that the files have the same path on both machines.  If this is not the case for you, a simple lookup table could be implemented in a bash script, and called in the Exec line.  You'll also want to have key based SSH access, so you don't need to input your password.  If the remote machine doesn't have ark installed, you could replace the ark call with unrar, unzip, etc.

The [Desktop Entry] section is used to specify the mimetypes the context menu is valid for, and specifies the action associated with the menu.

The [Desktop Action] section specifies the name used when rendering the menu, the icon that appears next to the name, and the Exec line. The Exec line ssh's to the remote host, cd's to the directory of the file that was selected, and runs ark's "extract here, autodetect subfolder" option.

See the freedesktop.org standards for more information about the Exec line and the variables available.