├── .editorconfig ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── README.md ├── examples ├── blink-chip.ts ├── blink.component.ts ├── blink.module.ts ├── blink.ts └── tsconfig.json ├── package.json ├── presentation.png ├── src ├── components │ ├── button.component.ts │ ├── led.component.ts │ └── seven-segment.component.ts └── index.ts ├── tsconfig.json └── tslint.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | insert_final_newline = false 15 | trim_trailing_whitespace = false 16 | 17 | [*.json] 18 | insert_final_newline = false 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | typings 3 | dist 4 | examples/aot 5 | examples/dist 6 | npm-debug.log 7 | compiled 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: false 3 | node_js: 4 | - '6' 5 | - '5' 6 | script: 7 | - npm test 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.4.0 (2017-05-06) 2 | 3 | * Package renamed to `angular-iot` 4 | 5 | ## 0.3.0 (2016-11-06) 6 | 7 | * Add `iot-seven-segment` component (interfaces I2C 4-digit 7-segment displays) 8 | 9 | ## 0.2.0 (2016-10-22) 10 | 11 | * Add support for bootstrapping NgFactory modules (for AoT+IoT projects) 12 | 13 | ## 0.1.1 (2016-10-14) 14 | 15 | * Include AoT (Ahead of Time) template compliation metadata in the NPM package 16 | 17 | ## 0.1.0 (2016-10-13) 18 | 19 | * Align with Angular 2 final and `angular-universal` 2.0 20 | 21 | ## 0.0.3 (2016-05-18) 22 | 23 | * Align with Angular 2.0.0-rc.1 and latest `angular-universal` (0.101.3) 24 | 25 | ## 0.0.2 (2016-04-26) 26 | 27 | * Align with latest `angular-universal` (0.98.3) 28 | 29 | ## 0.0.1 (2016-04-12) 30 | 31 | * Initial public release 32 | 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/urish/angular-iot.svg?branch=master)](https://travis-ci.org/urish/angular-iot) 2 | 3 | # Angular IoT 4 | > IoT support for Angular 5 | 6 | Angular IoT is an experimental technology that allows you to program physical hardware (buttons, LEDs, etc.) 7 | using Angular. It provides a set of directives, such as `` and `` that let you interface 8 | with the hardware. It is even possible to create an application that renders both a Web interface and an IoT (hardware) 9 | interface with a single code base. See [ng2-simon](https://github.com/urish/ng2-simon) for an example. 10 | 11 | Behind the scenes, it uses a combination of [angular-universal](https://github.com/angular/universal) for running 12 | the application inside Node.js, and the [johnny-five](https://github.com/rwaldron/johnny-five) library for 13 | interfacing with the hardware. 14 | 15 | # Building & Running the Blink example 16 | 17 | ## Arduino 18 | 19 | The [Blink Example](https://github.com/urish/angular-iot/blob/master/examples/blink.ts) will blink the built-in 20 | LED on an Adruino board that is connected to your PC. You will need to upload the 21 | [StandardFirmata firmware](https://github.com/firmata/arduino) to your Arduino board first. 22 | 23 | git clone https://github.com/urish/angular-iot 24 | cd angular-iot 25 | npm install 26 | npm run example:build 27 | npm run example:run 28 | 29 | Note: The example program will try to detect the serial port that the Arduino 30 | is connected to automatically. You can manually specify the port name by 31 | setting the `SERIAL_PORT` environment variable prior to running the example. 32 | 33 | ## C.H.I.P. (9$ computer) 34 | 35 | [CHIP](https://www.getchip.com) is a tiny 9$ computer that has enough computing power to run Angular. 36 | It also has WiFi and Bluetooth built-in, which makes it an ideal IoT platform. There is a version of the [Blink 37 | Example](examples/blink-chip.ts) that runs on CHIP. In order to run it, make sure you have Node 6.x installed on 38 | your CHIP (you can install it via [nvm](https://github.com/creationix/nvm)), and the run the following commands: 39 | 40 | git clone https://github.com/urish/angular-iot 41 | cd angular-iot 42 | npm install 43 | npm install chip-io 44 | npm run example:build 45 | npm run example:chip 46 | 47 | The on-board Status LED should start blinking. 48 | 49 | # Presentation (April 2016) 50 | 51 | [![angular-iot Talk](presentation.png)](https://skillsmatter.com/skillscasts/7934-javascript-from-the-world-wide-web-to-the-world-of-iot#video) 52 | 53 | Check out [ng2-simon](https://github.com/urish/ng2-simon) for a complete example of using angular-iot for powering a game 54 | that can be run both inside the web browser and on real hardware. 55 | 56 | # License 57 | [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](/LICENSE) 58 | -------------------------------------------------------------------------------- /examples/blink-chip.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * A Blink example for Angular IoT. Run it on a C.H.I.P. board and 3 | * see the Status LED blinking. 4 | * 5 | * Prior to running this example, run the following command: 6 | * 7 | * npm install chip-io 8 | * 9 | * You can get a C.H.I.P. board for 9$ from https://getchip.com 10 | * 11 | * Copyright (C) 2016, Uri Shaked. License: MIT. 12 | */ 13 | 14 | import 'angular2-universal-polyfills'; 15 | 16 | import { bootstrap } from '../src/index'; 17 | const { Board } = require('johnny-five'); 18 | var ChipIO = require('chip-io'); 19 | 20 | import { setPinName } from './blink.component'; 21 | import { BlinkModule } from './blink.module'; 22 | 23 | setPinName('STATUS'); 24 | 25 | const board = new Board({ 26 | io: new ChipIO() 27 | }); 28 | 29 | board.on('ready', () => { 30 | bootstrap(BlinkModule); 31 | }); 32 | -------------------------------------------------------------------------------- /examples/blink.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | export let _pinName = '13'; // This is the LED pin on Arduino 4 | 5 | export function setPinName(value: string) { 6 | _pinName = value; 7 | } 8 | 9 | @Component({ 10 | template: ` 11 | 12 | ` 13 | }) 14 | export class BlinkComponent implements OnInit { 15 | ledState: boolean = false; 16 | pinName = _pinName; 17 | 18 | ngOnInit() { 19 | setInterval(() => { 20 | this.ledState = !this.ledState; 21 | }, 500); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/blink.module.ts: -------------------------------------------------------------------------------- 1 | import { Component, NgModule, OnInit } from '@angular/core'; 2 | import { IotModule } from '../src/index'; 3 | 4 | import { BlinkComponent } from './blink.component'; 5 | 6 | @NgModule({ 7 | imports: [IotModule], 8 | declarations: [BlinkComponent], 9 | bootstrap: [BlinkComponent] 10 | }) 11 | export class BlinkModule { 12 | } 13 | -------------------------------------------------------------------------------- /examples/blink.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * A Blink example for Angular IoT. Connect it to an Arduino board with 3 | * a Firmata firmware to start linking the built-in LED (connected to pin 4 | * number 13). 5 | * 6 | * You may need to specify your serial port name by settings the environment 7 | * variable SERIAL_PORT. 8 | * 9 | * Copyright (C) 2016, Uri Shaked. License: MIT. 10 | */ 11 | 12 | import 'angular2-universal-polyfills'; 13 | 14 | import { Board } from 'johnny-five'; 15 | import { bootstrap } from '../src/index'; 16 | 17 | import { BlinkModule } from './blink.module'; 18 | 19 | const board = new Board({ 20 | port: process.env.SERIAL_PORT 21 | }); 22 | 23 | board.on('ready', () => { 24 | bootstrap(BlinkModule); 25 | }); 26 | -------------------------------------------------------------------------------- /examples/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "removeComments": false, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "sourceMap": true, 10 | "lib": [ 11 | "es2015", 12 | "dom" 13 | ], 14 | "outDir": "dist" 15 | }, 16 | "exclude": [ 17 | "aot", 18 | "dist" 19 | ], 20 | "angularCompilerOptions": { 21 | "genDir": "aot", 22 | "skipMetadataEmit": true 23 | } 24 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-iot", 3 | "version": "0.4.0", 4 | "description": "IoT support for Angular", 5 | "scripts": { 6 | "build": "rimraf dist compiled && ngc", 7 | "test": "tslint src/**/*.ts && npm run build && npm run example:build", 8 | "example:build": "rimraf examples/dist examples/aot && ngc -p examples", 9 | "example:run": "node examples/dist/examples/blink", 10 | "example:chip": "node examples/dist/examples/blink-chip", 11 | "prepublish": "npm run build" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/urish/angular-iot.git" 16 | }, 17 | "keywords": [ 18 | "angular", 19 | "iot", 20 | "arduino", 21 | "robotics", 22 | "raspberry pi" 23 | ], 24 | "author": "Uri Shaked", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/urish/angular-iot/issues" 28 | }, 29 | "homepage": "https://github.com/urish/angular-iot#readme", 30 | "typings": "dist/index.d.ts", 31 | "main": "dist/index.js", 32 | "files": [ 33 | "dist", 34 | "src" 35 | ], 36 | "devDependencies": { 37 | "@angular/common": "2.1.0", 38 | "@angular/compiler": "2.1.0", 39 | "@angular/compiler-cli": "2.1.0", 40 | "@angular/core": "2.1.0", 41 | "@angular/http": "2.1.0", 42 | "@angular/platform-browser": "2.1.0", 43 | "@angular/platform-server": "2.1.0", 44 | "@types/johnny-five": "0.0.29", 45 | "@types/node": "6.0.45", 46 | "angular2-universal": "2.1.0-rc.1", 47 | "angular2-universal-polyfills": "2.0.11", 48 | "es6-shim": "0.35.1", 49 | "johnny-five": "0.10.1", 50 | "preboot": "2.1.2", 51 | "reflect-metadata": "0.1.3", 52 | "rimraf": "2.5.2", 53 | "rxjs": "5.0.0-beta.12", 54 | "tslint": "3.15.1", 55 | "typescript": "2.0.3", 56 | "zone.js": "0.6.25" 57 | }, 58 | "peerDependencies": { 59 | "@angular/core": "^2.0.0", 60 | "@angular/common": "^2.0.0", 61 | "@angular/compiler": "^2.0.0", 62 | "@angular/platform-server": "^2.0.0", 63 | "@angular/platform-browser": "^2.0.0", 64 | "johnny-five": "^0.10.0" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /presentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/urish/angular-iot/8d467f96ad86087cae23631ab0df16b2994b3050/presentation.png -------------------------------------------------------------------------------- /src/components/button.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, Input, Output, EventEmitter, NgZone} from '@angular/core'; 2 | import * as five from 'johnny-five'; 3 | 4 | @Component({ 5 | selector: 'iot-button', 6 | template: '[Button on {{pin}} - {{state}}]' 7 | }) 8 | export class IotButtonComponent implements OnInit { 9 | @Input() pin: string | number; 10 | @Input() pullup: boolean = true; 11 | @Output() click = new EventEmitter(); 12 | 13 | private _button: five.Button; 14 | 15 | constructor(private zone: NgZone) { 16 | } 17 | 18 | ngOnInit() { 19 | this._button = new five.Button({ 20 | pin: this.pin, 21 | isPullup: this.pullup 22 | }); 23 | 24 | this._button.on('down', () => { 25 | this.zone.run(() => { 26 | this.click.emit({ 27 | pin: this.pin 28 | }); 29 | }); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/components/led.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnChanges, Input} from '@angular/core'; 2 | import * as five from 'johnny-five'; 3 | 4 | @Component({ 5 | selector: 'iot-led', 6 | template: '[LED on {{pin}} - {{state}}]' 7 | }) 8 | export class IotLEDComponent implements OnChanges { 9 | @Input() pin: string | number; 10 | @Input() state: boolean; 11 | 12 | private _led: five.Led; 13 | 14 | ngOnChanges(changes) { 15 | if (this.pin && !this._led) { 16 | this._led = new five.Led(this.pin); 17 | } 18 | if (this.state) { 19 | this._led.on(); 20 | } else { 21 | this._led.off(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/components/seven-segment.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input, OnChanges} from '@angular/core'; 2 | const {Board} = require('johnny-five'); 3 | 4 | const sevenSegmentAddress = 0x71; 5 | 6 | /** 7 | * Use with an I2C Seven Segement display, such as this one: 8 | * https://www.sparkfun.com/products/11441 9 | */ 10 | @Component({ 11 | 'selector': 'iot-seven-segment', 12 | 'template': '' 13 | }) 14 | export class IotSevenSegmentComponent implements OnChanges { 15 | @Input() value: string | number = null; 16 | private io; // initialized by Board.Component 17 | 18 | constructor() { 19 | Board.Component.call(this, {}); 20 | this.io.i2cConfig({}); 21 | } 22 | 23 | ngOnChanges() { 24 | if (this.value !== null) { 25 | const chars = this.value.toString().substr(0, 4).split('').map(letter => letter.charCodeAt(0)); 26 | try { 27 | this.io.i2cWrite(sevenSegmentAddress, [0x76, ...chars]); 28 | } catch (e) { 29 | console.log('Error: I2C Write failed', e.toString()); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { Type, Provider, NgModule, NgModuleFactory, NgModuleRef } from '@angular/core'; 2 | import { NodeModule, NodeHttpModule, NodeJsonpModule } from 'angular2-universal/node/node'; 3 | import { platformUniversalDynamic } from 'angular2-universal/node/universal-module'; 4 | 5 | import { IotLEDComponent } from './components/led.component'; 6 | import { IotButtonComponent } from './components/button.component'; 7 | import { IotSevenSegmentComponent } from './components/seven-segment.component'; 8 | 9 | declare var Zone: any; 10 | 11 | export const AngularIotDirectives = [ 12 | IotButtonComponent, 13 | IotLEDComponent, 14 | IotSevenSegmentComponent 15 | ]; 16 | 17 | @NgModule({ 18 | declarations: AngularIotDirectives, 19 | exports: AngularIotDirectives, 20 | imports: [ 21 | NodeModule, 22 | NodeHttpModule, // Universal Http 23 | NodeJsonpModule // Universal JSONP 24 | ] 25 | }) 26 | export class IotModule { } 27 | 28 | export function bootstrap(moduleType: Type, extraProviders: Array = []): Promise> { 29 | const zone = Zone.current.fork({ 30 | name: 'Angular 2 IoT', 31 | properties: { 32 | document: '' 33 | } 34 | }); 35 | return zone.run(() => { 36 | const platform = platformUniversalDynamic(extraProviders); 37 | return platform.bootstrapModule(moduleType); 38 | }); 39 | } 40 | 41 | export function bootstrapFactory(moduleFactory: NgModuleFactory, 42 | extraProviders: Array = []): Promise> { 43 | const zone = Zone.current.fork({ 44 | name: 'Angular 2 IoT', 45 | properties: { 46 | document: '' 47 | } 48 | }); 49 | return zone.run(() => { 50 | const platform = platformUniversalDynamic(extraProviders); 51 | return platform.bootstrapModuleFactory(moduleFactory); 52 | }); 53 | } 54 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "removeComments": false, 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "sourceMap": true, 10 | "lib": ["es2015", "dom"], 11 | "outDir": "dist" 12 | }, 13 | "exclude": [ 14 | "node_modules", 15 | "dist", 16 | "examples", 17 | "compiled" 18 | ], 19 | "angularCompilerOptions": { 20 | "genDir": "compiled" 21 | } 22 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "class-name": true, 4 | "comment-format": [ 5 | true, 6 | "check-space" 7 | ], 8 | "curly": true, 9 | "eofline": true, 10 | "forin": true, 11 | "indent": [ 12 | true, 13 | "spaces" 14 | ], 15 | "label-position": true, 16 | "label-undefined": true, 17 | "max-line-length": [ 18 | true, 19 | 140 20 | ], 21 | "no-arg": true, 22 | "no-bitwise": false, 23 | "no-console": [ 24 | true, 25 | "debug", 26 | "info" 27 | ], 28 | "no-construct": true, 29 | "no-debugger": true, 30 | "no-duplicate-key": true, 31 | "no-duplicate-variable": true, 32 | "no-empty": false, 33 | "no-eval": true, 34 | "no-string-literal": false, 35 | "no-switch-case-fall-through": true, 36 | "trailing-comma": true, 37 | "no-trailing-whitespace": false, 38 | "no-unused-expression": true, 39 | "no-unused-variable": false, 40 | "no-unreachable": true, 41 | "no-use-before-declare": true, 42 | "no-var-keyword": false, 43 | "one-line": [ 44 | true, 45 | "check-open-brace", 46 | "check-catch", 47 | "check-else", 48 | "check-whitespace" 49 | ], 50 | "quotemark": [ 51 | true, 52 | "single" 53 | ], 54 | "radix": true, 55 | "semicolon": [ 56 | true, 57 | "always" 58 | ], 59 | "object-literal-sort-keys": false, 60 | "triple-equals": [ 61 | true, 62 | "allow-null-check" 63 | ], 64 | "variable-name": false, 65 | "whitespace": [ 66 | true, 67 | "check-branch", 68 | "check-decl", 69 | "check-operator", 70 | "check-separator", 71 | "check-type" 72 | ] 73 | } 74 | } --------------------------------------------------------------------------------