配線
obnizからサーボやLEDなどに配線をしているが、obnizとの接続部分が、今一つ気に入らない状態。 オスピンに配線をつないでいるのだが、かなり丸出しな感じなので、よくないと思う。 そこでもう少し改善を図ってみようと思う。

単純なオスピンでそのまま配線しているので、これを下段に基盤を配置するなどして、少し安定するようにしてみたい。 基板へのオスピン設置と、サーボやLEDにはコネクタを介して接続するようにしてみる。 LEDはLED内蔵スイッチを使用し、点灯しているLEDを押しても、施錠/開錠動作ができるようにする。

これで、多少きれいにできるだろうか? では、実際に基板にオスピンとコネクタを実装し、はんだ配線をする。 なんとなくそれっぽいものが出来た。これでうまくいくかな?

リードスイッチは既存のものを使用。 途中でぶった切って、コネクタ接続しておく。

LEDスイッチはこちら。青と赤を使用する。 現在の施錠状態を赤(施錠中)か青(開錠中)で表示しつつ、どちらでもボタンとして押せば、 逆動作(施錠→開錠/開錠→施錠)をさせる予定。わざわざボタンを押すということは、変化させたい時だと思うので、 このような仕様としてみる。

基板の設置を考えて、スマートロックも土台部分の設計を修正した。さて、これで印刷開始だ。
印刷と組立
設計変更したスマートロックをとっとと印刷出力する。とはいえ、結構な時間がかかるので、 何日かかけて出力する。土台、シリンダー部、上蓋、ギア、と出力。ノブ回しのレバーは前回のをそのまま流用。

取り付けのねじ類なども前回のものを流用。基本的なつくりは同じなので、取り付けもほぼ同様となっている。

まずは土台部分に磁石を取り付ける。かなりちょうどサイズだったスペースに、磁石を入れてねじ止め。 それなりに強力な磁石なので、しっかり扉に密着する。

中段のシリンダー部にはサーボが取り付けられる。 また配線類も考えていかなければいけない。 サーボ、リードスイッチ、LEDスイッチ2個を取り付けつつ組み立てる。

まずはサーボを取り付け。この段階では緩めに取り付けておく。最終締め付けはギアをつけてから。

次にギア側の準備。扉の鍵のノブを回す部分。真ん中にベアリングを入れて回りやすくする。

サーボをはめ込み、ギアを装着。サーボ側のギアを取り付けるために、サーボにサーボホーンを取り付ける。 ここにサーボ側のギアを取り付ける。ちょっとギアのかみ合わせがキツキツ。 でも実際に動かしてみると問題なく動作したので、問題なさそう。

サーボへのギアをはめる前に、ふた取付用のナットをあらかじめ仕込んでおく必要あり。何度か忘れてギア取り外しを実施。 ナットを入れてからギアをはめ込めばギアが邪魔でナットは外れない。

土台と合体を実施。obnizは後で差し込めないので、あらかじめ装着させておく。 天板に取り付けるLEDを出した状態でほかの配線は押し込んで取付。 配線をすっきりさせる目的だったが、あまり効果は無かった。

最後に天板にスイッチ付きのLEDを取り付ける。穴に溝が入れてあるので、ここに配線を通してやる。 スイッチ自体はバネで引っかかるようになっている。

とりあえず完成。さて、使用感はどうだろうか?

nodejs
プログラム側もスイッチ追加や使用ピン変更があるので、いくつか修正を行う。
//****************************************
// ライブラリ定義
//****************************************
const Obniz = require("obniz");
const express = require('express');
const path = require('path');
const fs = require('fs');
const log4js = require('log4js');
const logger = log4js.getLogger();
const app = express();
//****************************************
// obniz定義
//****************************************
let obnizID_Btm = "{下側obniz}"; // 下側obniz
let obnizID_Top = "{上側obniz}"; // 上側obniz
const sockName = 'smartlock'; // socket用イベント名
const PIN_SERVO_GND = 0
const PIN_SERVO_VCC = 1
const PIN_SERVO_SIGNAL = 2
const PIN_LED_RED = 3
const PIN_PUSH_SW_RED = 4
const PIN_LED_GREEN = 5
const PIN_PUSH_SW_GREEN = 6
const PIN_REEDSWITCH_SIGNAL = 7
const PIN_REEDSWITCH_GND = 10
// 状態管理
const sendingTime = 1000; // アクション後の待ち時間
let OpenPwmDuty = 30; // 開錠時のLED明るさ
let ClosePwmDuty = 30; // 施錠時のLED明るさ
let servoWait = 600; // サーボが90度動く待ち時間
let sending = false; // socket送信中フラグ
let servoMoved = false; // サーボ動作中フラグ
let servo_enable = [true, true]; // 上下側サーボ使用有無
//****************************************
// Logger定義
//****************************************
//log4js-config
log4js.configure({
appenders: {
system: {type: 'file', filename: 'system.log', maxLogSize: 4194304, backups: 3, compress: true},
console: {type: 'console'},
access: {type: 'file', filename: 'access.log', maxLogSize: 4194304, backups: 3, compress: true}
},
categories: {
default: {appenders:['system', 'console'], level: 'debug'},
web: {appenders: ['access'], level: 'debug'}
}
});
const systemLogger = log4js.getLogger();
const accessLogger = log4js.getLogger('web');
app.use(log4js.connectLogger(accessLogger));
//****************************************
// 使用するobnizと変数定義
//****************************************
var obniz = new Array(2); // obniz用意
obniz[0] = new Obniz(obnizID_Top); // 上側obniz定義
obniz[1] = new Obniz(obnizID_Btm); // 下側obniz定義
var obnizExists = [false, false]; // obnizの接続状態
var buttonStatus = [false, false]; // ロック状態
// パーツ定義
var button = [null, null]; // ボタン
var servo = [null, null]; // サーボ
var pwmOpen = [null, null]; // 開錠中
var pwmClose = [null, null]; // 施錠中
var pushSwR = [null, null]; // 開閉ボタン(Red)
var pushSwG = [null, null]; // 開閉ボタン(Green)
/*------------------------------------------------------------
obnizのDisplay用画面準備
------------------------------------------------------------*/
// canvas作成
const { createCanvas } = require('canvas');
const width = obniz[1].display.width;
const height = obniz[1].display.height;
const ctxOpen = createCanvas(width, height).getContext('2d');
const ctxClose = createCanvas(width, height).getContext('2d');
// 描画
ctxOpen.fillStyle = "white";
ctxOpen.font = "40px Arial";
ctxOpen.fillText("Open", 0, 60);
ctxClose.fillStyle = "white";
ctxClose.font = "40px Arial";
ctxClose.fillText("Close", 0, 60);
// 初期表示
systemLogger.info('SmartLock Server Starting...');
systemLogger.info('obniz ID(Top) is ' + obnizID_Top);
systemLogger.info('obniz ID(Btm) is ' + obnizID_Btm);
/*------------------------------------------------------------
Express処理
------------------------------------------------------------*/
// Crossを有効
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS');
next();
});
// Options
app.options('*', (req, res) => {
res.sendStatus(200);
});
app.use(function (req, res, next) {
res.removeHeader('X-Powered-By');
res.removeHeader('ETag');
res.header('Cache-Control', ['private', 'no-store', 'no-cache', 'must-revalidate', 'proxy-revalidate'].join(','));
res.header('no-cache', 'Set-Cookie');
next();
});
// routing(ローカルのファイルを使用[vue作成])
app.use(express.static(path.join(__dirname, 'public')));
//****************************************
// API処理定義
//****************************************
// API
app.get('/', function(req, res) {
// サンプル用
res.send('Hello obniz!');
});
app.get('/open', function(req, res) {
// 開錠(全サーボ動作)
smartLockServo(false);
var ret = { sts: true, lock: false, msg: 'door is unLocked' }
res.send(ret);
});
app.get('/close', async function(req, res) {
// 施錠(全サーボ動作)
await smartLockServo(true);
var ret = { sts: true, lock: true, msg: 'door is Locked' }
res.send(ret);
});
app.get('/status', async function(req, res) {
// 状態
var stsTop = true; // 上段obniz状態
var stsBtm = true; // 下段obniz状態
if (button[0]) {
// 上段のロック状態確認(open:true, close:false)
buttonStatus[0] = await button[0].isPressedWait();
} else {
stsTop = false;
}
if (button[1]) {
// 下段のロック状態確認(open:true, close:false)
buttonStatus[1] = await button[1].isPressedWait();
} else {
stsBtm = false;
}
// 応答メッセージ作成
var ret = { sts0: stsTop, sts1: stsBtm,
lock0: buttonStatus[0], lock1: buttonStatus[1],
ledopen: OpenPwmDuty, ledclose: ClosePwmDuty, servowait: servoWait }
res.send(ret);
});
/*------------------------------------------------------------
obniz処理
①obnizOnconnect:obnizの接続
②obnizOnchange :リードスイッチの状態変化
------------------------------------------------------------*/
obniz[0].onconnect = async function() {
/*------------------------------------------------------------
初期処理実行
------------------------------------------------------------*/
obnizOnconnect(0);
/*------------------------------------------------------------
状態チェック用のリードスイッチ処理
------------------------------------------------------------*/
// 変化を検知したら、表示
button[0].onchange = function(locked) {
obnizOnchange(locked, 0);
};
/*------------------------------------------------------------
開閉用ボタン処理
------------------------------------------------------------*/
// 変化を検知したら、動作
pushSwR[0].onchange = function(pressed) {
if (pressed) {
// 開閉動作
smartLockServo(!buttonStatus[0]);
}
};
pushSwG[0].onchange = function(pressed) {
if (pressed) {
// 開閉動作
smartLockServo(!buttonStatus[0]);
}
};
}
obniz[1].onconnect = async function() {
/*------------------------------------------------------------
初期処理実行
------------------------------------------------------------*/
obnizOnconnect(1);
/*------------------------------------------------------------
状態チェック用のリードスイッチ処理
------------------------------------------------------------*/
// 変化を検知したら、表示
button[1].onchange = function(locked) {
obnizOnchange(locked, 1);
};
/*------------------------------------------------------------
開閉用ボタン処理
------------------------------------------------------------*/
// 変化を検知したら、動作
pushSwR[1].onchange = function(pressed) {
if (pressed) {
// 開閉動作
smartLockServo(!buttonStatus[1]);
}
};
pushSwG[1].onchange = function(pressed) {
if (pressed) {
// 開閉動作
smartLockServo(!buttonStatus[1]);
}
};
}
/*------------------------------------------------------------
obniz初期処理
------------------------------------------------------------*/
async function obnizOnconnect(obnizNo) {
// 接続完了
obnizExists[obnizNo] = true;
systemLogger.info('obniz[' + obnizNo + '] is connected');
// 接続時初回送信
if (io) {
// この段階ではほぼsocketが出来ていないので、この送信は行われない。
io.emit(sockName, { event: 'connect', sts0: obnizExists[0], sts1: obnizExists[1],
obnizid0: obnizID_Top, obnizid1: obnizID_Btm, obnizno: obnizNo,
msg: 'obniz[' + obnizNo + '] is connecting' });
}
/*------------------------------------------------------------
状態表示用のLED準備
------------------------------------------------------------*/
// LED定義
pwmOpen[obnizNo] = obniz[obnizNo].getFreePwm(); // 開錠LED用PWM
pwmOpen[obnizNo].start({io:PIN_LED_GREEN}); // 開錠中LED
pwmOpen[obnizNo].duty(0); // まずは消灯
pwmClose[obnizNo] = obniz[obnizNo].getFreePwm(); // 施錠LED用PWM
pwmClose[obnizNo].start({io:PIN_LED_RED}); // 施錠中LED
pwmClose[obnizNo].duty(0); // まずは消灯
/*------------------------------------------------------------
状態チェック用のリードスイッチ処理
------------------------------------------------------------*/
// リードスイッチ定義
button[obnizNo] = obniz[obnizNo].wired("Button", {signal:PIN_REEDSWITCH_SIGNAL, gnd:PIN_REEDSWITCH_GND});
/*------------------------------------------------------------
開閉用ボタン処理
------------------------------------------------------------*/
// ボタン入力定義(Red側)
pushSwR[obnizNo] = obniz[obnizNo].wired("Button", {signal:PIN_PUSH_SW_RED, gnd:PIN_REEDSWITCH_GND});
// ボタン入力定義(Red側)
pushSwG[obnizNo] = obniz[obnizNo].wired("Button", {signal:PIN_PUSH_SW_GREEN, gnd:PIN_REEDSWITCH_GND});
/*------------------------------------------------------------
錠操作用のサーボ処理
------------------------------------------------------------*/
// サーボ定義
servo[obnizNo] = obniz[obnizNo].wired("ServoMotor", {gnd:PIN_SERVO_GND, vcc:PIN_SERVO_VCC, signal:PIN_SERVO_SIGNAL});
// センター位置へ初期移動
servo[obnizNo].angle(90.0);
/*------------------------------------------------------------
本体スイッチ操作
------------------------------------------------------------*/
obniz[obnizNo].switch.onchange = async function(state) {
if (state == 'none') {
// 何もしない
} else if (state == 'push') {
// 全員にsocket送信
systemLogger.info('Switch[' + obnizNo + '] Pushed!');
io.emit(sockName, { event: 'push', obnizno: obnizNo , msg: 'switch[' + obnizNo + '] pushed!!!' });
} else if (state == 'left') {
// 施錠
await smartLockServo(true);
} else if (state == 'right') {
// 開錠
await smartLockServo(false);
}
}
}
/*------------------------------------------------------------
状態チェック用のリードスイッチ処理
------------------------------------------------------------*/
async function obnizOnchange(locked, obnizNo) {
systemLogger.info('(onChange)[' + obnizNo + ']-1-(lock:' + locked + ')');
buttonStatus[obnizNo] = locked;
if (locked) {
// 表示(施錠中)
obniz[obnizNo].display.clear();
obniz[obnizNo].display.draw(ctxClose);
pwmOpen[obnizNo].duty(0); // 消灯[Open]
pwmClose[obnizNo].duty(ClosePwmDuty); // 点灯[Close]
setTimeout(function() {
// 表示クリア
obniz[obnizNo].display.clear();
}, 10000);
} else {
// 表示(開錠中)
obniz[obnizNo].display.clear();
obniz[obnizNo].display.draw(ctxOpen);
pwmOpen[obnizNo].duty(OpenPwmDuty); // 点灯[Open]
pwmClose[obnizNo].duty(0); // 消灯[Close]
setTimeout(function() {
// 表示クリア
obniz[obnizNo].display.clear();
}, 10000);
}
// 全員にsocket送信
// 送信開始
sending = true;
if (io) {
if (obnizNo === 0) {
io.emit(sockName, { event: 'onchange', lock0:locked, msg: locked?'door0 is Locked!':'door0 is Locked!' });
} else {
io.emit(sockName, { event: 'onchange', lock1:locked, msg: locked?'door1 is Locked!':'door1 is Locked!' });
}
systemLogger.info('(onChange)[' + obnizNo + ']-2- socket sended');
}
}
/*------------------------------------------------------------
開錠・施錠ボタン処理
------------------------------------------------------------*/
async function smartLockServo(lock) {
var servoAngle = lock?13:167;
// サーボがまだ動作中かチェック
if (!servoMoved) {
servoMoved = true; // 動作中セット
for(var i = 0;i < 2; i++) {
// 各サーボ存在チェック
if (servo[i] && servo_enable[i]) {
// サーボ動作
servo[i].angle(servoAngle);
// wait
await obniz[i].wait(servoWait);
// サーボを元の位置に戻す
servo[i].angle(90.0);
// wait
await obniz[i].wait(servoWait);
}
}
// 動作終了
servoMoved = false;
}
}
/*------------------------------------------------------------
obniz切断処理
------------------------------------------------------------*/
async function obnizOnclose(obnizNo) {
// 切断
obnizExists[obnizNo] = false;
button[obnizNo] = null;
pushSwR[obnizNo] = null;
pushSwG[obnizNo] = null;
servo[obnizNo] = null;
systemLogger.info('obniz[' + obnizNo + '] is disconnect');
// 送信
if (io) {
io.emit(sockName, { event: 'disconnect', sts0: obnizExists[0], sts1: obnizExists[1], obnizid: (obnizNo==0)?obnizID_Top:obnizID_Btm, obnizno: obnizNo, msg: 'obniz[' + obnizNo + '] is disconnect' });
}
}
/*------------------------------------------------------------
obniz切断時の処理
------------------------------------------------------------*/
obniz[0].onclose = async function() {
obnizOnclose(0);
}
obniz[1].onclose = async function() {
obnizOnclose(1);
}
/*------------------------------------------------------------
ログ用日付
------------------------------------------------------------*/
function nowDatetime() {
var dt = new Date();
return '[' + dt.getFullYear() + '/' + ('0' + String(dt.getMonth()+1)).slice(-2) + '/' + ('0' + dt.getDate()).slice(-2)
+ '-' + ('0' + dt.getHours()).slice(-2) + ':' + ('0' + dt.getMinutes()).slice(-2) + ':' + ('0' + dt.getSeconds()).slice(-2)
+ '.' + ('00' + dt.getMilliseconds()).slice(-3) + '] ';
}
/*------------------------------------------------------------
Express Server起動
------------------------------------------------------------*/
// Server
var server = app.listen(3300, function() {
systemLogger.info('Example app listening on port:' + server.address().port)
});
//****************************************
// socket.ioセッティング
//****************************************
var io = require('socket.io')(server);
// クライアントが接続してきたときの処理
io.sockets.on('connection', function(socket) {
systemLogger.info('(socket)connection');
// クライアント一覧
getClients();
// 送信
socket.emit('message', { msg: 'SmartLock',
sts0: obnizExists[0], sts1: obnizExists[1],
obnizid0: obnizID_Top, obnizid1: obnizID_Btm });
// 受信
socket.on('message', function(data) {
systemLogger.info('(socket)message:' + JSON.stringify(data));
});
// クライアントが切断したときの処理
socket.on('disconnect', function(){
systemLogger.info('(socket)disconnect');
// クライアント一覧
getClients();
});
// クライアント一覧取得
function getClients () {
io.clients(function(error, clients) {
systemLogger.info('(socket)connect users:' + clients);
});
}
});pin10をLEDやスイッチのすべての共通GNDにしている。
ボタンが押されると、[buttonStatus]が現在の鍵の状態を保持しているので、 その反対になるような動作を実行する。(190,196,221,227)
obniz本体の画面表示はもうケース内となって見えないので表示の意味は無いのと、 表示させっぱなしだと、画面が焼き付くので、デバッグ向けに表示後10秒で消えるようにした。(314,324)