LoginSignup
0
1

More than 5 years have passed since last update.

Electric ImpでiPhoneからLチカしてみる。

Posted at

基本的に本家のGet Startedの Agents and Internet of Things Apps を少しカスタマイズして、iPhoneアプリからLチカする一連のコードを記載します。

実行イメージ

アプリ側 electric imp
IMG_0126.PNG スクリーンショット 2017-12-09 23.46.33.png
iphone-app.png スクリーンショット 2017-12-09 23.47.19.png

Electric Impの面白いところ

editor.png

ブラウザ上でコードを組んだらそれが実機に反映されて、Wifi経由の動作コマンドをすごく少ないコードで実装できること。
標準で気温 / GPS / ジャイロセンサーを搭載しているので、ベーシックなセンサー動作の実装が非常に簡単。
コードを追えていないのですが、SalesForce / IBM Watson / PLCなんかとの接続もできるようなので、かなり簡単に外部Webサービスとの連携もできそうです。

Electric Impにコード実装

Agents and Internet of Things AppsのAgentとDeviceのコードをカスタマイズし、RGBのカラーコードを受け取れるようにします。

Agent.

// 受信パラメータ r g b を
// led = 1 [On] or 0 [Off] 
// r = Red   [0..255]
// g = Green [0..255]
// b = Blue  [0..255]
function requestHandler(request, response) {
    try {
        if ("led" in request.query) {
            if (request.query.led == "1" || request.query.led == "0") {
                local ledState = (request.query.led == "0") ? false : true;

                // データはArrayで送る
                device.send("set.led", [ledState, request.query.r, request.query.g, request.query.b]); 
            }
        }

        response.send(200, "OK");
    } catch (ex) {
        response.send(500, "Internal Server Error: " + ex);
    }
}

http.onrequest(requestHandler);
Device.
#require "WS2812.class.nut:3.0.0"

spi <- null;
led <- null;

function setLedState(data) {
    // data[0] = On / Off
    // data[1] = Red   [0..255]
    // data[2] = Green [0..255]
    // data[3] = Blue  [0..255]
    local color = data[0] ? [data[1].tointeger(), data[2].tointeger(), data[3].tointeger()] : [0,0,0];
    led.set(0, color).draw();
}

spi = hardware.spiAHSR;
spi.configure(MSB_FIRST, 6000);

led = WS2812(spi, 1);
hardware.pinH.configure(DIGITAL_OUT, 1);

// Agentのdevice.sendで呼び出されるメソッド名に応じたDevice実装関数を呼び出す
agent.on("set.led", setLedState);

iPhoneにコード実装

コード

Podfile.
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'ledSwitch' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for ledSwitch
  pod 'Gryphon', '~> 3.1'
  pod 'Font-Awesome-Swift'
end
ViewController.swift
import UIKit
import Gryphon
import Font_Awesome_Swift

class ViewController: UIViewController {
    @IBOutlet weak var lblAppICON: UILabel!
    @IBOutlet weak var lblColor: UILabel!
    @IBOutlet weak var sldRed: UISlider!
    @IBOutlet weak var sldGreen: UISlider!
    @IBOutlet weak var sldBlue: UISlider!
    @IBOutlet weak var btnChange: UIButton!
    @IBOutlet weak var btnStop: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        // アプリケーションロゴ設定
        lblAppICON.FAIcon = FAType.FARssSquare

        // 実行ボタンのアイコンやカラー設定
        btnChange.layer.borderWidth = 1.0
        btnChange.layer.cornerRadius = 4.0
        btnChange.setFAText(prefixText: "Change ", icon: FAType.FAPowerOff, postfixText: "", size: 24.0, forState: .normal, iconSize: 24.0)
        btnChange.setFATitleColor(color: UIColor.white)
        btnChange.backgroundColor = UIColor(displayP3Red: CGFloat(72.0 / 255.0), green: CGFloat(165.0 / 255.0), blue: CGFloat(109.0 / 255.0), alpha: 1.0)
        btnChange.layer.borderColor = btnChange.backgroundColor?.cgColor

        // 停止ボタンのアイコンやカラー設定
        btnStop.layer.borderWidth = 1.0
        btnStop.layer.cornerRadius = 4.0
        btnStop.layer.borderColor = UIColor.darkGray.cgColor
        btnStop.setFAText(prefixText: "Lights out ", icon: FAType.FAStopCircleO, postfixText: "", size: 24.0, forState: .normal, iconSize: 24.0)
        btnStop.setFATitleColor(color: UIColor.white)
        btnStop.backgroundColor = UIColor.darkGray

        // スライダで設定したカラーのプレビュー
        lblColor.layer.borderWidth = 1.0
        lblColor.layer.cornerRadius = 8.0
        lblColor.clipsToBounds = true
        lblColor.text = ""
        sldRed.value = 1
        sldGreen.value = 0
        sldBlue.value = 0
        lblColor.backgroundColor = UIColor(displayP3Red: CGFloat(sldRed.value), green: CGFloat(sldGreen.value), blue: CGFloat(sldBlue.value), alpha: 1.0)
        lblColor.layer.borderColor = lblColor.backgroundColor?.cgColor
    }


    @IBAction func changeRGBColor(_ sender: Any) {
        // 色変更をプレビュー表示する
        lblColor.backgroundColor = UIColor(displayP3Red: CGFloat(sldRed.value), green: CGFloat(sldGreen.value), blue: CGFloat(sldBlue.value), alpha: 1.0)
        lblColor.layer.borderColor = lblColor.backgroundColor?.cgColor
    }

    @IBAction func doLedColorSet(_ sender: Any) {
        // GryphonでAPIをコール
        API
            .Messages
            // Device側は0..255の値になるので、0..1の値を変換
            .getMessage(onOff: 1, red: Int(sldRed.value * 255), green: Int(sldGreen.value * 255), blue: Int(sldBlue.value * 255))
            .response { (result) in
                switch result {
                case let .response(statusCode):
                    print("StatusCode=\(statusCode)")
                case let .error(error):
                    print("Error=\(error)")
                }
        }
    }

    @IBAction func doStopLight(_ sender: Any) {
        API
            .Messages
            .getMessage(onOff: 0, red: 0, green: 0, blue: 0)
            .response { (result) in
            switch result {
            case let .response(statusCode):
                print("StatusCode=\(statusCode)")
            case let .error(error):
                print("Error=\(error)")
            }
        }
    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}
API.swift
import Foundation
import Gryphon

final class API {
    /*
     * Your common property or function.
     */
}

extension API {

    final class Messages: Requestable {

        // required `Requestable`
        static var baseURL: String {
            return "https://agent.electricimp.com/"
        }

        // required `Requestable`
        static var path: String {
            return "デバイスのコード"
        }

        // Returns message(String) from server or error reason(Error).
        class func getMessage(onOff: Int, red: Int, green: Int, blue: Int) -> Task<String, Error> {
            let task = Task<String, Error> { result in
                // 普通にURL形式で送る
                let url = URL(string: baseURL + path + "?led=" + onOff.description + "&r=" + red.description + "&g=" + green.description + "&b=" + blue.description)!
                var request = URLRequest(url: url)
                request.httpMethod = "GET"
                let session = URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in
                    guard let data = data,
                        let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [AnyObject],
                        let message = json?[0]["result"] as? String else {
                            result(.error(ResponseError.unexceptedResponse(error as AnyObject)))
                            return
                    }
                    result(.response(message))
                })
                session.resume()
            }
            return task
        }

        // Returns status code if the submittion is succeeded.
        class func postMessage() -> Task<Int, Error> {
            let task = Task<Int, Error> { result in
                let url = URL(string: baseURL + path)!
                var request = URLRequest(url: url)
                request.httpMethod = "POST"
                let session = URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in
                    guard let statusCode = (response as? HTTPURLResponse)?.statusCode else { return }
                    if 200...299 ~= statusCode {
                        result(.response(statusCode))
                    }else{
                        result(.error(ResponseError.unacceptableStatusCode(statusCode)))
                    }
                })
                session.resume()
            }
            return task
        }
    }
}

量産になるといろいろ超えるべきハードルがありますが、
プロトタイピングでとにかく早く、手軽にという目的であれば
これはすごくいいツールなんじゃないかなぁと思っています。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1