alohas – alexa homeskill helper in nodejs

Tôi làm việc với Echo một thời gian, để phát triển ứng dụng trợ lý ảo Alexa cho home automation.

Nếu bạn làm việc với Alexa, bạn sẽ biết rằng nó có 2 phần: home skill và custom skill. Home skill dùng để điều khiển các ứng dụng tự động trong ngôi nhà, ví dụ Alexa, set temperature to 20 degree là câu tôi thường dùng khi đến văn phòng.

Custom skill thì không giới hạn các lện bật tắt, thiết lập như homeskill; nó rộng hơn. Có lẽ vậy nên Amazon ưu tiên hỗ trợ sdk cho custom skill trước https://github.com/alexa/alexa-skills-kit-sdk-for-nodejs.

Để bổ xung phần còn lại, tôi viết một sdk để giúp bạn phát triển ứng dụng home skill dễ dàng, nhanh chóng hơn, cũng trên nền nodejs. Tôi gọi nó là alehos – alexa home skill kit https://github.com/nqd/alehos.

Phần readme miêu tả khá kỹ các sử dụng kit này.

Hy vọng nó có ích cho bạn.

CI của gitlab

Đến thời điểm hiện nay, tôi thường yêu cầu các dự án của mình phải có CI. Nếu viết bằng script như nodejs thì CI sẽ có nhiệm vụ check syntax, để các thành viên trong nhóm cùng một kiểu viết giống nhau, và chạy các mức test khác nhau như unit test, CDC test.

Điểu tuyệt vời của gitlab là nó đi kèm với bộ CI miễn phí cho cả dự án private (yay). Blog này tôi sẽ trình bày chiến lược để thiết lập env test trên Gitlab CI để build docker image, và upload nó lên gitlab registry.

 

Gitlab runner

Là nơi chương trình test của bạn sẽ được chạy. Bạn có thể có một PC riêng biệt cho việc build và test. Gitlab cung cấp một chương trình khá tiện https://gitlab.com/gitlab-org/gitlab-ci-multi-runner để thiết lập runner cục bộ. Cá nhân tôi chỉ sử dụng multi runner này khi chương trình cần tài nguyên lớn.

Phần lớn thời gian tôi sử dụng shared runner https://about.gitlab.com/gitlab-com/settings/#shared-runners. Xin cảm ơn sự tử tế của Digital Ocean khi cho mỗi build một tài nguyên 4GB chạy trong mỗi máy ảo riêng biệt.

Shared runner chạy trên docker, nên có thể khai báo các docker có sẵn khá tiện (yay).

.gitlab-ci.yml

Là file cấu hình cho gitlab ci. Dưới đây là một ví dụ trong đó khai báo một trạng thái của test pipeline là unit test. Phần sau dựa trên giả thuyết tôi đang xây dựng một web app với nodejs, và chạy unit test với npm run test.

image: node:boron-alpine

stages:
 - unit_test

unit_test_job:
 stage: unit_test
 script:
 - npm install
 - npm run test

Với mỗi git push lên CI được trigger. CI sẽ pull về docker image node:boron-alpine giống với docker chạy trong staging và production environment của web app này. Stages khai báo các bước của CI. Trong trường hợp này, tôi chỉ có một bước duy nhất là unit test khai báo trong unit_test_job.

Đơn giản như vậy.

Nhưng, vì tôi tin vào 12factor, và tôi muốn có quá trình build trước. CI hay staging hay production sẽ khác nhau ở env truyền vào docker như trình bày ở https://12factor.net/build-release-run. Tôi sẽ tạo một job để tạo artifact, và chạy test trên artifact này.

image: docker:1.12
services:
 - docker:dind

stages:
 - build

variables: 
 CONTAINER_TEST_IMAGE: registry.gitlab.com/company/project:$CI_BUILD_REF_NAME
before_script:
 - docker info
build_image_job:
 stage: build
 script:
 - docker build -t $CONTAINER_TEST_IMAGE .
 - docker run $CONTAINER_TEST_IMAGE npm run test

Setup này sử dụng docker trong docker (dind)  để build docker image trong một docker (nơi CI này đang chạy). Đều này đạt được do shared runner chạy với privileged enable (wao).

Như vậy lúc này CI sẽ tạo một docker có tên biến CONTAINER_TEST_IMAGE , và chạy test trong image này.

Tôi muốn tiến thêm một bước nữa, pipeline bao gồm: build, test, và release. Quá trình release xảy ra khi tôi tag git tag -a version, nó sẽ tạo ra tag latest và upload lên gitlab registry.

Khoa, gitlab registry? Đúng vậy, gitlab cho phép bạn lưu các image lên host của họ. Bạn sẽ có CI, và registry (miễn phí).

image: docker:1.12

services:
- docker:dind

stages:
- build
- test
- release
- deploy

variables:
 CONTAINER_TEST_IMAGE: registry.gitlab.com/company/project:$CI_BUILD_REF_NAME
 CONTAINER_RELEASE_IMAGE: registry.gitlab.com/company/project:latest

before_script:
 - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.gitlab.com

build:
 stage: build
 script:
 - docker build --pull -t $CONTAINER_TEST_IMAGE .
 - docker push $CONTAINER_TEST_IMAGE

unit_test:
 stage: test
 script:
 - docker pull $CONTAINER_TEST_IMAGE
 - docker run $CONTAINER_TEST_IMAGE npm run unit_test

cdc_test:
 stage: test
 script:
 - docker pull $CONTAINER_TEST_IMAGE
 - docker run $CONTAINER_TEST_IMAGE npm run cdc_test

release-image:
 stage: release
 script:
 - docker pull $CONTAINER_TEST_IMAGE
 - docker tag $CONTAINER_TEST_IMAGE $CONTAINER_RELEASE_IMAGE
 - docker push $CONTAINER_RELEASE_IMAGE
 only:
 - tags
 - triggers

Gitlab rất hào phóng khi cung cấp đầy đủ các công cụ và dịch vụ để bạn có thể xây dựng một quá trình CI khá hoàn chính, từ việc chạy các test đến việc lưu trữ các image của bạn.

Hy vọng bạn sẽ tìm thấy sự hữu dụng trong ecosystem của gitlab để xây dựng hệ thống bền vững.

Sử dụng AWS IoT

 

logo-iot

 

Trước đây tôi thường tận dụng mã nguồn mở để thiết lập MQTT broker để kết nối đến các thiết bị. Một số dự án mà tôi đã sử dụng có thể kể đến như Mosquitto, hay Mosca.

Với prototype, các chương trình này thực hiện rất tốt công việc của mình: thiết lập nhanh, và miễn phí :D.

Và đến mức độ nào đó, tôi gặp phải điểm yếu của chúng: Mosquitto không scale tốt, dù ai đó nói với tôi rằng hãy dùng chức năng bridge, tôi vẫn cho rằng nó không phải là các thức để scale. Mosquitto không cung cấp cơ chế authen/author rõ ràng. Mosca là một dự án khá nối tiếng về broker trên nền Node.js. Hình thức bảo mật của Mosca là thông qua username/pass cho mỗi kết nối. Vì viết bằng JS, nên khả năng mở rộng để tôi có thể hook function này quản lý mỗi kết nối khá tiện. Tuy nhiên Mosca như Mosquitto không thể cluster được.

Cuối năm 2015, AWS bổ sung gói IoT trong menu của họ, dưới dạng SaaS. Một số đặc điểm của AWS IoT có thể kể đến như:

  • scale, scale, scale.
  • bảo mật
  • liên kết dịch vụ khác, như lambda, dynamodb.

Thấy rằng AWS IoT đáp ứng được các nhu cầu cho một broker trong hệ thống kết nối, tôi viết lên vài dòng ở đây, xem như ghi chú của cá nhân vậy.

AWS IoT cung cấp gì

Bản thân là một SaaS broker, tôi sẽ sử dụng nó để kết nối đến các thiết bị thông qua MQTT. Vì nó cung cấp bởi AWS, broker này kỳ vọng sẽ ổn định, và hiện hữu trong một thời gian không ngắn.

AWS IoT định nghĩa một số thuật ngữ như:

  • Thing: là một đối tượng, tương đương với thiết bị nào đấy. Thing được kết nối với các principal thông qua policy.
  • Certificate: chứng chỉ X.509 mà các thực thể (principal) sử dụng để kết nối đến broker thông qua giao thức MQTT. Do đó, các client phải hỗ trợ SSL layer để làm việc với AWS IoT, tạo lớp bảo mật đầu tiên.
  • Policy: chính sách được áp dụng vào các Certificate tương ứng. Policy cung cấp cơ chế bảo mật tiếp theo, bằng cách quy định ai (mqtt client id) có thể connect được, và hình thức (pub/sub topic) làm việc.
  • Rule: để kết nối AWS IoT này với các dịch vụ khác, như đẩy dữ liệu qua Lambda hay lưu vào DynamoDB.

Có thể hình dung qúa trình tôi cần làm để kết nối một đối tượng (gọi D) của tôi vào AWS IoT, và sử dụng điện thoại (gọi A) để kết nối đến client này thông qua MQTT, trong đó tất cả các thông điệp đều được chuyển đến DynamoDB như sau:

  • Tạo hai Certificate, một cho A, một cho D.
  • Tạo một Thing, tôi đặt tên là doi-tuong-D.
  • Attach A và D vào thing doi-tuong-D.
  • Tạo hai policy. Bên dưới (*) là một ví dụ của policy cho phép mọi quyền kết nối và topic làm việc, gọi là policyA, policyD tương ứng. Attach policyA vào A, policyD vào D.

Lúc này nếu app A gởi (pub) lên command/req, thì thiết bị D sẽ nhận được khi nó đăng ký (sub) cũng trên cùng một chủ đề command/req.

Tôi muốn lưu các command này vào DB để xử lý về sau, tôi sẽ thiết lập một rule, gọi là ruleD. Rule được sử dụng để kích hoạt kết nối giua IoT và dịch vụ khác của AWS.

Đưới đây là mô hình diễn tả mối quan hệ của A và D.

blog-aws-iot-example

Tích hợp AWS IoT vào hệ thống

AWS cung cấp dashboard để tôi có thể thực hiện các bước trên, nhưng dĩ nhiên tôi không thể tiến hành bằng tay những công đoạn trên cho mỗi thiết bị/app được thêm vào. AWS cung cấp SDK (https://github.com/aws) để kết nối đến API của tất cả các dịch vụ của họ. Tôi sẽ xem AWS IoT như một serivce có nhiệm vụ làm broker.

Cuối cùng, tôi cần viết một microservice khác để quản lý các thing, cert, rule, và tạo các policy tương ứng với mức logic của ứng dụng.

Thay cho lời kết, cần lưu ý rằng Microsoft hay IBM đều cung cấp nhánh IoT trong dịch vụ đám mây của họ. Với nhiều sự lựa chọn như vậy, tôi nghĩ mình không nên nghĩ đến việc tự xây dựng lấy một broker trong hoàn cảnh hiện này.

(*) Một policy đơn giản cho phép hết các quyền kết nối và các chủ để pub/sub.


{
    "Version": "2012-10-17",
    "Statement": [{
        "Effect": "Allow",
        "Action": [
            "iot:*"
        ],
        "Resource": ["*"]
    }]
}

 

 

npm install package from private repo

My company hosts most of the private repositories in gitlab, thanks to its generous unlimited-free-plan, and wonderful built-in CI.

npm need to get package from private gitlab, or bitbucket: create tag, and provide direct link when install package.

First: tag package with version (e.g. 0.0.1)

git tag -a v0.0.1 -m "first release"
git push origin v0.0.1

, then tell npm the link with tag. I will love to use git+ssh instead of git+https since my CI runner and collaborators already have the right to get access to this repo; thus don’t need to enter password every time npm try to install.

npm install git+ssh://git@gitlab.com:company/repo.git#v0.0.1 --save

Không, IFTTT

Tôi làm làm việc với một công ty camera, họ có khoảng vài trăm ngàn user. Lãnh đạo nghe ngóng thấy IoT có vẻ hot, liếc qua thấy các công ty Cam khác đều có nhãn IFTTT. Nhiệm vụ được đặt ra: gắn mác IFTTT lên sản phẩm.

IFTTT cung cấp cơ chế nếu – thì cho các dịch vụ mạng. Tuy nhiên phải nó IFTTT khá tệ trong việc cung cấp thông tin cho các dịch vụ khác tích hợp vào. Điều khiến tôi khá thất vọng là cho đến thời điểm tôi viết bài này, không một hướng dẫn nào của IFTTT cho developer để làm việc với dịch vụ của họ. Cái duy nhất tôi thấy là Partnership Inquiries.

Điền vào form này, chờ vài ngày, không có trả lời. Điền lại lần 2 cũng không thấy trả lời. WTF.

Gởi email cho họ trực tiếp, tôi nhận được trả lời như sau:

Thank you for your interest in IFTTT. We’ve received your request to join our partner platform. Given the influx of Channel submissions, we aren’t in a position to move forward at this time. However, because you’ve shared your information with us, we’ll be sure to be in touch when we have more to share.

Nghĩa là sẽ chờ không biết bao giờ stack của họ mới được giải phóng, oppp.

Nhu cầu về tự động dịch vụ đến thời điểm này khá phổ biến đến mức có một số khác tựa như IFTTT ra đời, kể đến như Zapier, WeWiredWeb, Elastic.io.

Liếc qua Zapier, họ có ít các app được kết nối hơn, nhưng tài liệu hỗ trợ cho devl thì tuyệt vời. Zapier cung cấp chi tiết cách thức để tôi có thể tích hợp với backend của mình, thông qua một loạt ví dụ. Tôi có thể tạo private app trước khi public nó. Điểm cộng cho Zapier.

hiển thị đồ thị trên web

Trong quá trình viết chương trình quản lý mạng cảm biến, một vấn đề khó nuốt tôi gặp phải là hiển thị biểu đồ các thông số hệ thống, giá trị cảm biến. Tôi chọn nền tảng web chứ không phải là desktop app vì một số lý do, như tương thích đa nền tảng.

Đối tượng đầu tiên nhắm đến là rrdtool (bonus thêm phần cơ sở dữ liệu thời gian thực). rrdtool được dùng trong rất nhiều trình ứng dụng quản lý mạng dựa trên snmp. Tuy nhiên, sau một thời gian sử dụng, rrdtool thật không ưng ý, vì cách hiển thị của nó quá đơn điệu trên file ảnh tỉnh png. Thêm nữa, cơ sở dữ liệu thời gian thực rrdtool đòi hỏi xác định thời gian cập nhật ngay lúc khởi tạo, điều này có thể không thích hợp với mạng cảm biến, khi mà tần số cập nhật có thể thay đổi thường xuyên.

Tôi không muốn dùng flash.

Javascript là sự lựa chọn tiếp theo. Các thư viện, thương mại và miễn phí, js vẽ đồ thị rất nhiều. Sau một hồi cân đo đong đếm, tôi dừng lại với highcharts. Highcharts tính phí cho sản phẩm thương mại, và miễn phí cho sản phẩm “dùng chơi”. Nghĩa là tôi có thể sử dụng miễn phí vào thời điểm hiện nay :). Hiển thị của highcharts ở dạng 2D, khá đẹp, và có tính tương tác với người dùng.

Tôi tạo một project django với highchart, và khá bất ngờ  với sự đơn giản mà highchart api đem lại (Project nằm ở https://github.com/nqd/chartit-exam).

Một công cụ khác tôi rất thích khi đọc về khả năng của nó, nhưng chưa sử dụng được là graphite. Graphite được xây dựng dựa trên tư tưởng cơ sở dữ liệu thời gian thực của rrdtool, nhưng phần đồ thị kết hơp giữa file ảnh tĩnh và js nên mang tính tương tác cao.

Nếu bạn thấy tôi bỏ sót công cụ nào, rất vui lòng được trao dổi cùng.