Andrea Rovai
Published © Beerware

Web-based light dimmer

Remote control lights at home using a UDOO Board, a PIC Micro, Android and a Polymer framework to build the UI of the web app.

Full instructions provided4,025
Web-based light dimmer

Things used in this project

Hardware components

PIC16F88
×1
UDOO QUAD
UDOO QUAD
×1

Story

Read more

Code

file_12264.txt

Plain text
#include <sys/stat.h>

#include <sys/types.h>

#include <termios.h>

#include <unistd.h>



static uint8_t dimmer_values[4];  // Brightness for each channel (0-255).



...



static int update_dimmers(void) {

  uint8_t i;

  int fd = open(tty, O_RDWR | O_NOCTTY | O_NDELAY);

  if (fd < 0) {

    perror("Cannot open tty");

    return -1;

  }



  struct termios tio;

  if(tcgetattr(fd, &tio) < 0) {

    perror("tcgetattr");

    return -1;

  }



  tio.c_cflag &= ~(IGNBRK | BRKINT | ICRNL |

                    INLCR | PARMRK | INPCK | ISTRIP | IXON);

  tio.c_oflag = 0;

  tio.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);

  tio.c_cflag &= ~(CSIZE | PARENB);

  tio.c_cflag |= CS8;



  if(cfsetispeed(&tio, B2400) < 0 || cfsetospeed(&tio, B2400) < 0) {

    perror("cfsetispeed");

    return -1;

  }



  if(tcsetattr(fd, TCSAFLUSH, &tio) < 0) {

    perror("tcsetattr");

    return -1;

  }



  // Update the four dimmer channels.

  uint8_t buf[sizeof(dimmer_values)];

  for (i = 0; i < sizeof(dimmer_values); ++i) {

    const uint8_t value = 0x3F - ((dimmer_values[i] >> 2) & 0x3F);

    buf[i] = value | (i << 6);

  }

  write(fd, buf, sizeof(buf));

  close(fd);

  return 0;

}

file_12267.txt

Plain text
GET /dimmer/0 HTTP/1.1

HOST: udoo:8080



# ---- SERVER RESPONSE ----

HTTP/1.1 200 OK

Content-Type: text/plain



255  # The light is fully on

            

file_12268.txt

Plain text
Type in a caption
POST /dimmer/0 HTTP/1.1

HOST: udoo:8080

Content-Length: 2



10  # Set the light almost off

file_12269.txt

Plain text
// Prototypes of the REST handlers, one per request method and path.

static bool REST_dimmer_get(const char* path, struct mg_connection *conn);

static bool REST_dimmer_post(const char* path, struct mg_connection *conn);



struct rest_endpoint_t {

  const char* uri;

  const char* method;

  bool (*handler)(const char*, struct mg_connection*);

};





// List of registered REST handlers.

const struct rest_endpoint_t endpoints[] = {

  {"/dimmer/", "GET",  REST_dimmer_get},

  {"/dimmer/", "POST", REST_dimmer_post},

  ...

};





// Invoked upon GET /dimmer/N.

// Returns the brightness of the N-th dimmer (0: off, 255: max brightness).

static bool REST_dimmer_get(const char* path, struct mg_connection *conn) {

  const uint8_t channel = atoi(path);

  if (channel >= sizeof(dimmer_values))

    return false;

  mg_printf_data(conn, "%d", dimmer_values[channel]);

  return true;

}





// Invoked upon POST /dimmer/N

// Sets the brightness of the N-th dimmer (0: off, 255: max brightness).

static bool REST_dimmer_post(const char* path, struct mg_connection *conn) {

  const uint8_t channel = atoi(path);

  if (channel >= sizeof(dimmer_values))

    return false;

  char val[4];

  strncpy(val, conn->content, MIN(conn->content_len, sizeof(val) - 1));

  dimmer_values[channel] = atoi(val);

  update_dimmers();

  mg_printf_data(conn, "OK\n");

  return true;

}





// Actual mongoose HTTP handler. Checks whether the request method and path

// match any registered endpoint.

static int http_handler(struct mg_connection *conn, enum mg_event ev) {

  uint32_t i;

  switch (ev) {

    case MG_REQUEST:

      for (i = 0; i < ARRAY_SIZE(endpoints); ++i) {

        const struct rest_endpoint_t* ep = &endpoints[i];

        const size_t uri_len = strlen(ep->uri);

        if (strcmp(conn->request_method, ep->method) == 0 &&

            strncmp(conn->uri, ep->uri, uri_len) == 0) {

          // Invoke the corresponding REST_* function.

          if (ep->handler(&conn->uri[uri_len], conn))

            return MG_TRUE;

        }

      }

      return MG_FALSE;

    case MG_AUTH:

      return MG_TRUE;  // No HTTP auth, assume LAN is trusted.

    default:

      return MG_FALSE;

  }

}





// Finally, the web-service entry-point.

int main() {

  struct mg_server *server;

  server = mg_create_server(NULL, http_handler);

  mg_set_option(server, "listening_port", "8080");



  for (;;) {

    // Blocks at most for some (60) ms, so we get a chance to re-trigger the

    // watchdog on the PIC if there is no REST request.

    mg_poll_server(server, 60);

    update_dimmers();

  }

}

file_12272.txt

Plain text
<paper-slider value="{{value}}" max="255" id="dimmer"></paper-slider>

<!-- For the GET requests -->
<core-ajax auto url="{{ajaxurl}}/dimmer/{{channel}}" handleAs="text" response="{{value}}" loading="{{loading}}">
</core-ajax>

<!-- For POST updates -->
<core-ajax auto="{{!loading}}" url="{{ajaxurl}}/dimmer/{{channel}}" method="POST" handleAs="text" body="{{value}}">
</core-ajax>

file_12273.txt

Plain text
<polymer-element name="home-automation">

       <template>
         <style>
         ... (see complete example in the source code)
         </style>

        <core-toolbar id="core_toolbar">
           <core-icon-button icon="menu" id="core_icon_button" on-tap="{{reset_all}}">
           </core-icon-button>
           <div id="div" flex>Home Automation</div>
        </core-toolbar>

        <core-card id="dimmers" class="card" layout vertical>
          <home-automation-dimmer channel="0" id="dimmer0" color="gold">
            </home-automation-dimmer>
          <home-automation-dimmer channel="1" id="dimmer1" color="green">
            </home-automation-dimmer>
          <home-automation-dimmer channel="2" id="dimmer2" color="red">
            </home-automation-dimmer>
          <home-automation-dimmer channel="3" id="dimmer3" color="navy">
            </home-automation-dimmer>
        </core-card>
       </template>
  </polymer-element>
            

Github

Credits

Primiano Tucci

Posted by Andrea Rovai

Comments