Motivation

Drupal 8 is out the door – well, the release candidate at least, so it's time to get intimate with it. As I'm mostly a backend developer with a focus on coding, I'm mostly interested in what's under the hood: how should we write a new module. As we had our heating system upgraded this summer and I opted for a controller that can be instructed via the web, it was an extra motivational factor: it would be nice to have a heating system #madewithdrupal8. :)

Every proper project should:

  1. set the goals first;
  2. come up with a specification that the client/user can understand;
  3. come up with a specification for the coders which includes the data model;
  4. provide some possible later improvement ideas.

Don't expect a "usual" D8 introduction: there’s going to be no speaking about .yml files and structuring the code – there are quite a few of them already out there. I'm going to speak only about my own experiences.

Goals

My goals weren't too high with this project. Honestly, the biggest one was trying to have one of my interests coincide with leveling up in my daily job.

  • Tinycontrol (TC from now on) reports all that it can to a Drupal 8 site of the user's choosing as TC cannot keep logs itself.
  • Every Drupal user can have up to one private TC log.
  • Diagrams of all logged data can be displayed of the last day, week, month or year, with minimum and maximum data displayed with dates.
  • These diagrams should be visible on my stone-age Android phone's default browser. (This is why I can't rely solely on Thingspeak.com.)
  • Learn about D8 while doing all of these.

Considerations

  • TC's "Remote URL" may be max. 127 characters, and it should start with "GET /tc" (7 chars).
  • For security and authentication reasons, the "Remote URL" should contain a write key. Thingspeak uses 16 chars as write key (user-configurable). TC has up to 25 different values to report.
  • Every TC value is encoded as "#XX", so every field eats up 5 chars + separator: "&f=#XX".
  • Conclusion: with 16 chars as key every user can submit up to 16 values. With 15 chars this limit increases to 17 values: "GET /tc?w=123456789012345&a=#XX&b=#XX&c=#XX&…&o=#XX&p=#XX&q=#XX"

Data model

tc_user table

  • uid: unsigned int NOT NULL DEFAULT 0
  • write_key: varchar(15) DEFAULT NULL
  • settings: blob (serialized) DEFAULT NULL

tc_data table

  • uid: unsigned int(10) NOT NULL DEFAULT 0
  • timestamp: int(11) NOT NULL DEFAULT 0
  • field_id: char(1) NOT NULL DEFAULT 'A'
  • field_value: varchar(7) DEFAULT NULL

Functions

User settings (web UI, form)

Provide UI for user to enter:

  • Write key (15 chars, with a random-generated default)
    • Validate uniqueness amongst users
  • For each of the 17 fields:
    • Enabled
    • Name

Data submit (service, page controller)

Provide callback for TC to submit data:

  • As TC does not have any error handling, the Drupal module simply does not store anything if the W field (write key) is unknown.
  • The Drupal module simply stores the first 7 chars for each field, it does not validate the data.

Data display (web UI, page controller)

Provide UI for user to display every enabled fields' data for the past day, week, month and year, using some charting API. (Probably https://www.drupal.org/project/visualization as it seems to be the only one so far with a #D8CX pledge.)

Later improvements

Data import (done) (web UI, form)

Provide UI for users to import their previous data (preferably using the same syntax Thingspeak uses for export).

Data export

Provide UI for users to export their data (preferably using the same syntax Thingspeak uses).

Expose Chart.js settings

Provide UI for users to change some Chart.js settings.

Views integration

For all the data but the settings.

Rules support

So the site owners can set up some rules/actions eg. send users an email when their TC reports above-threshold temperature.

Connecting to Tinycontrol

Usual setup for a TC is a home/office/lab automation tool, behind a firewall with an ever-changing IP address. There aren't too many free dynamic DNS providers, and this functionality depends on the DSL router/firewall. Dynamic DNS is not really needed if TC is set up to submit data every now and then: the Drupal module could store the last IP the TC has connected from, and the users could provide the port they have set up as a forward on for their TC. If the Drupal module knows the IP, the port and the credentials needed for TC, then it should be possible to control TC from a Drupal site – even through a firewall.

Caveats and gotchas during coding

With a decent D7 coder background I thought I knew the main pain factors. Some of them turned out to be the main gain factors, luckily.

  • Rendering a diagram into a dynamic PNG to have my phone understand it is technically possible, but hey, we're in the 21st century. That's how I found Chart.js, which was easier to integrate into my module than anticipated. (I have even played with an extension of it which promised easier date/time display, but that didn't work on my phone.)
  • As much of what I learned about coding was from Knuth's The Art of Computer Programming when the bounty was under a thousand dollars, getting a bit more intimate with OOP while coding for D8 was a must.
  • I was afraid of the new Twig system, being the new theming layer, but it turned out that for my basic theming needs there was no real change. The Batch and Schema APIs is surprisingly the same as in D7 (at least those parts I have used).
  • There are hardly any contrib modules available for D8, so far.. I have even run into several that might have worked in the past, but weren't functional when I tried them.
  • I had some hard time finding how to do this and that, because my D7 skills weren't always good enough, and D8 is so new there aren't too many usable examples. Additionally reading the code requires some alternative thinking, since procedural and object-oriented stuff should be read with two distinctive mindsets. (And I haven't mentioned those classy factorized trait baits.)
  • Don't even think about trying to write D8/OOP code using vim. That's gonna be an epic fail by itself. I tried. Then my colleague helped me to set up a proper IDE, which was the best idea so far.
  • I still have to learn quite a few things regarding D8. Don't take my code as a standard to follow – only as an example that's working somewhat.
  • The code is available on drupal.org. Feel free to send a patch! :)

About the author

CSÉCSY László

Senior Developer, Drupal Architect

László has been a backend developer since he met Drupal in 2007. He has experience in HTML, PHP, MySQL, Git, Linux server administration, mentoring, and even a slight touch of jQuery. His main interests are interoperability, architectural discovery, gardening, music score engraving and volunteer church work.