I have altered my curtain automation. Pray I do not alter it further.

Arduino-Based Curtain Automation, Mk 2:

Come for the not-quite-competent hardware hacking, stay for the snark about the Arduino Ethernet library!

Previously, previously.

Tags: , ,

25 Responses:

  1. Jeremy says:

    "I mean, it's written in Java, so complaining about how relentlessly terrible it is really feels like kicking a puppy. A puppy with no hind legs."

    And yet somehow it still really feels good to kick that puppy.

  2. Gabriel Rosenkoetter says:

    Just a heads up: perhaps out of embarrassment over the 3.0 software, it appears Griffin's left https://griffintechnology.com/desktop/powermate as a 404 (with an animated GIF of... cats boxing in bondage gear?). I guess it was too much trouble for them to redirect from "desktop" to "us" (or, I guess, presumed locale of visitor).

    But, you know, maybe leave the link to the boxing cats. It's kind of amusing.

  3. Jim Sweeney says:

    You made me LOL.

  4. John Adams says:

    I will soon have a curtain automation problem in the bedroom. I think I am just going to opt for the motorized rods as they are finally down in the $2k range.

    They also advised that on 18 feet of curtain you really want two panels to avoid motor issues, so I guess I'm doing that (they guarantee overlap and no light in the center)

    I forgot to ask you, how did you get these curtains made? We bought our own fabric and we're paying the same company to put the rod in and make the curtains.

    • I bought the curtains at a bulk fabric place in Potrero that no longer exists; then a few years later, I paid a friend of Susan's to sew a better blackout lining onto them.

    • John Adams says:

      Ah, ok. We went with a 100% blackout liner and a similar velvet to yours (although purple instead of blue to match the green walls.)

  5. Patrick says:

    At least with regard to #7, there's an option in the Arduino prefs to use an external editor which turns the "IDE" into a compiler and flasher, leaving editing right out of things.

    It's still pretty lousy for a decade old project, though.

  6. Jason says:

    To ask a question that may or may not be stupid: How does the torque on your current, barely-strong-enough-and-slow motor compare to the motor in a hefty cordless drill? Is it possible to rig one of those up dialed to a setting with enough oomph to open the curtain but not so slow that you fall back asleep before it's done?

  7. Your bit about the Ethernet MAC reminded me of when I was working on a project to stand up Pandaboards for testing Firefox on Android. The board has a built-in Ethernet port, but it also doesn't have an EEPROM with a MAC baked-in. Also the Ethernet port was actually attached to the USB bus, so due to some quirk of Linux kernel architecture the driver couldn't generate a fixed MAC based on other hardware IDs. There was a patch that got submitted upstream and rejected (of course) that generated a fixed MAC based on some other onboard hardware. This wouldn't have been a problem except for the fact that we were trying to deploy 800 of them rack-mounted in a datacenter, so we needed fixed MAC addresses to make PXE-booting and DNS work properly. I wound up having to rebuild the kernel (what else?) to include that non-upstreamed patch to make things work.

  8. PJ says:

    I never understood the economics of the Arduino Ethernet shield: Arduino $15 + Ethernet shield $45 = $60 vs Raspi or BeagleBoneBlack for ~$30. The BBB comes with 4GB of onboard flash to hold a debian variant vs the Raspi with onboard audio but runs from a (micro)SD card. And they both have plenty of GPIOs and/or PWM channels.

    • jwz says:

      That does seem like some crazy-assed economics. I guess the downsides of a raspi include: 45 seconds to boot and the surety that eventually your appliance will participate in a botnet.

      • rcn says:

        They're targeted to different types of users: The Raspi is for kids to learn python and the Arduino is for kids to mount simple hardware kits.
        Neither cover your problem in an acceptable way, sadly.

        The Arduino is merely an $3 ATmega with a custom bootloader, an USB-to-UART converter and a crappy linear voltage regulator, running very VERY lame software.
        The Raspberry Pi is cheap and all that, but the hardware is admittedly unreliable and I wouldn't trust my curtains, let alone a critical appliance, to software running on top of an oversized Debian distro put together by a bunch of ADHD kids that are more concerned about gnome widgets than security.

        You can always write the software from scratch on top of the Raspi SoC but, you know, ARM CPUs...

  9. Bill Paul says:

    I was curious to see just how the ethernet shield was implemented so I took a look at the one you used. Then I looked up the "Wiznet W5500" chip.

    Now I see the violence inherent in the system.

    The ATmega328 on the Arduino Uno has very limited resources (32KB of flash, 2KB of EEPROM and 2KB of SRAM). Trying to cram a software TCP/IP stack in there, along with driver support for an ethernet chip, and still have space left over for any application code just isn't going to fly. One full sized ethernet frame would eat up all your RAM. Apparently they solved this using an ethernet chip that has the TCP/IP stack baked into it. It has hardware _sockets_, for crying out loud.

    It looks like it does not have its own built-in DHCP client though, so that part has to be done in software on the Arduino. Again, given the constraints of the ATmega328, creating a full function DHCP client is tricky at best. The lack of lease renewal is... not unexpected. The DHCP server sends the lease expiration time along with the lease, and you have to be able to handle whatever it tells you (within the rules of the DHCP spec anyway). Let's say you have to renew every 5 minutes. The ATmega328 doesn't have a time of day clock, so how do you know when 5 minutes has gone by? It does have timers, but I don't think the interval registers are large enough that you can set a delay of 5 minutes. Maybe you can set up a 1 second ticker, then re-trigger your DHCP request when you've counted 300 seconds. Of course then you need have to actually write the code to handle the logic of renewing your lease (rather that just acquiring one) which will eat up more of your flash.

    Also, I'm not sure how easy that would be to integrate into the Arduino "sketch" framework. (In my own tinkering with this stuff, I said "screw this Arduino crap" and went straight for AVR GCC, but I've got issues, not the least of which is that I will sometimes write code in C without being paid to.)

    Also, link detect _is_ hard. The hard part is doing it asynchronously. It used to be the case that most VxWorks ethernet drivers did exactly what you observed here: when you called the driver start routine, it would sit there for several seconds waiting for a link to come up. If you didn't have a network cable plugged in, link negotiation would just time out, and the start routine would either return failure or else it would just hard code the interface for an arbitrary speed and duplex setting and cross its fingers. If you plugged the cable in later, no link-renegotiation would happen. If the driver set the MAC for 100Mbps full duplex and you plugged in cable to a 1Gbps switch, you'd be SOL. The timeout also varied depending on the driver, and the boot process would be stalled until it finished because the link detection was being done synchronously. (If you had a board with 4 or 5 ethernet ports and only one was plugged in, you might be stuck waiting for a couple of minutes for it to boot.) I finally got tired of that crap and added asynchronous link management, but the only reason I could make that work is that with VxWorks I could have it done in a background task. You can't do multitasking on the ATmega328.

    Looking at the datasheet for the Wiznet chip, there is one register you can use to initialize autonegotiation and subsequently determine the link state. Again, you could use a timer to set up a 1 second ticker and poll the link state on every tick until the link comes up. I suppose somebody decided it was simpler to just use a busy-wait loop in the Begin method instead.

    A two minute timeout is definitely excessive though. According to the specs, link autoneg shouldn't take more than about 5 seconds. Maybe the timeout loop is using a hard coded delay value that doesn't match your actual system clock frequency.

    As for the MAC address thing, you're right. Looking at the datasheet, there are both source and destination MAC address registers. The expectation is that software on the Arduino will program the source registers to set the station address. I suppose if you were mass producing these things, it would be your job to ensure they all have unique addresses. You could modify the software to read the MAC address out of the ATmega328's EEPROM storage and just provision each device with a unique address as it comes off the assembly line. But you're not doing that, are you. This is just a hobby project. So you're right: they should have put an EEPROM on the ethernet shield and given each one a unique address. Even better, they could have rigged it so that the address is auto-loaded into the source MAC address register on power-up. Of course that would require the shield manufacturer to get an OUI assigned by the IEEE, which probably costs money.

    • jwz says:

      Given that there's an LED on the ethernet plug that does link-detect, it's hard to see how link-detect could still be hard.

      • Bill Paul says:

        That's because you have eyeballs. You can see that LED, but the Arduino can't. There's no interrupt pin to signal for the shield to signal to the ATmega328 when link changes occur, which means you can't tell it when the link is up: instead it has to ask. That means means polling, and that's where it gets messy.

        • jwz says:

          Given that electrons happen, I'm just positing that it is not RAM-busting rocket surgery to answer the question "do I have link." E.g., before diving down a two-minute wait-for-reply hole.

          • Bill Paul says:

            Given that the ATmega328 only has a series of GPIO pins to talk to the outside world, you have to use bit-banging to read or write any of the registers in the ethernet shield, which is a bit of pain. In this case, you get to decide what modes to advertise as part of the autoneg process and you can then view the result after autoneg finishes (speed, duplex and link up/down). Only once the link is up should you try sending any traffic.

            The only reason I can think of why they might wait for two minutes before timing out is that they're trying to account for the case where the user has powered up the device without the cable plugged in, and they're trying to give them more than just 5 seconds to connect it before giving up. (I.e. "One day there will be lemon-soaked napkins...")

            This assumes that plugging in the cable during that two-minute interval actually makes it work.

            Either that, or it's not just blocking waiting for link: it could also be blocking in the DHCP client code waiting on a lease. I can see waiting a while for that. It just sucks that you have to do this synchronously.

      • Bill Paul says:

        Test...

    • Ben says:

      (In my own tinkering with this stuff, I said "screw this Arduino crap" and went straight for AVR GCC, but I've got issues, not the least of which is that I will sometimes write code in C without being paid to.)

      Yes... (I also have some BSDmakefiles which let me avoid the GUI altogether.) Once I had made the mistake of looking at the source of some of the supplied libraries, I then couldn't unsee what I had seen, and the horror came oozing up out of the header files into my code and excision was the only option.

      (Also: C+fucking+?? On a machine where every byte of RAM is valuable?)

      You can't do multitasking on the ATmega328.

      You can, of course. A simple co-op task switcher is not a difficult thing to write; you just have to have libraries which work like that. If the Arduino people had put a bit of thought into designing a decent mini-OS the drivers could be made non-blocking and interrupt-driven without too much effort, and things like 'renew my lease in 5 minutes' would be easy.

      (In fact, it looks like the Ethernet class has code to renew the lease, you just need to call Ethernet.maintain regularly.)

  10. David Konerding says:

    Regarding the IDE and file saving- go to preferences and set "Use external editor", then just use the IDE for compiling and uploading. My team took the plunge and switched to Arduino-mk, which permits us to "make" from the command line.

    If I'm talking to a remote arduino and I'm dragging at least one cable to it, it's going to be a USB cable, not an ethernet cable. That way you get data and power (I don't believe in PoE).

    Generally, the wifi-capable arduinos are easier to use than the ethernet shields. It looks like the implementors chose to move the majority of the logic and resource to a separate microprocessor.

    I've also worked with boards that have BLE, which is a whole separate set of pain. But, it does look like it will be the most common network transport in future Arduinos. I've worked with the RedBear BLEND, using the Arduino-BLE library (https://github.com/sandeepmistry/arduino-BLEPeripheral), as well as the new Arduino 101 (using the CurieBle library that Intel bundles). Obviously, you need something that can talk to BLE devices, which can be a command line app on Mac OS X, the nRF Master Control Panel app on android (and ios?), or a custom app on android or ios. I wouldn't recommend this for anybody who doesn't work on this sort of thing full time and has a huge tolerance for crap.

  11. Wilko says:

    Since you are no longer using a stepper motor you don't really need the motor shield. You can just use a couple of relays driven by the digital IO pins - one for motor on/off and one with change-over contacts to reverse the direction. This way your motor size will be limited by the relay contact capacity, not the transistors in the motor shield. If you do go down this path make sure the software turns off the motor and waits a couple of seconds for it to stop before powering it on in the reverse direction

    • Wilko says:

      Actually, you could keep the motor shield and use it to switch the relays rather than driving the motor directly. The motor shield already has the 12v and protection diode stuff you would need anywau

  12. ssl-3 says:

    I like your Utopian vision and would like to subscribe to your newsletter.

  13. Kaleberg says:

    Consider the Arduino Yun. It's a bit more expensive ($70), but it is shield compatible with an Arduino and has a little Linino managing the Wifi. Boot to connect time is about a minute or two. It does DHCP. It configures by setting up its own Wifi net that you connect to and configure for your own WiFi. You talk to the Arduino by sending it URLs so you an use curl or a web browser to control it.

    It's not magic, but the little Barbie dream house Linux box makes it network usable. (I use it for a lamp and for our Christmas tree topper.)

  • Previously