[update] Blocklyのコードジェネレータの仕様変更に対応

This commit is contained in:
ocogeclub 2023-08-19 08:53:45 +09:00
parent 82db8193d2
commit ef353e0650
24 changed files with 151 additions and 1675 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,171 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function, unicode_literals
import time
import pigpio
class DHT11(object):
"""
The DHT11 class is a stripped version of the DHT22 sensor code by joan2937.
You can find the initial implementation here:
- https://github.com/srounet/pigpio/tree/master/EXAMPLES/Python/DHT22_AM2302_SENSOR
example code:
>>> pi = pigpio.pi()
>>> sensor = DHT11(pi, 4) # 4 is the data GPIO pin connected to your sensor
>>> for response in sensor:
.... print("Temperature: {}".format(response['temperature']))
.... print("Humidity: {}".format(response['humidity']))
"""
def __init__(self, pi, gpio):
"""
pi (pigpio): an instance of pigpio
gpio (int): gpio pin number
"""
self.pi = pi
self.gpio = gpio
self.high_tick = 0
self.bit = 40
self.temperature = 0
self.humidity = 0
self.either_edge_cb = None
self.setup()
def setup(self):
"""
Clears the internal gpio pull-up/down resistor.
Kills any watchdogs.
"""
self.pi.set_pull_up_down(self.gpio, pigpio.PUD_OFF)
self.pi.set_watchdog(self.gpio, 0)
self.register_callbacks()
def register_callbacks(self):
"""
Monitors RISING_EDGE changes using callback.
"""
self.either_edge_cb = self.pi.callback(
self.gpio, pigpio.EITHER_EDGE, self.either_edge_callback
)
def either_edge_callback(self, gpio, level, tick):
"""
Either Edge callbacks, called each time the gpio edge changes.
Accumulate the 40 data bits from the dht11 sensor.
"""
level_handlers = {
pigpio.FALLING_EDGE: self._edge_FALL,
pigpio.RISING_EDGE: self._edge_RISE,
pigpio.EITHER_EDGE: self._edge_EITHER,
}
handler = level_handlers[level]
diff = pigpio.tickDiff(self.high_tick, tick)
handler(tick, diff)
def _edge_RISE(self, tick, diff):
"""
Handle Rise signal.
"""
val = 0
if diff >= 50:
val = 1
if diff >= 200: # Bad bit?
self.checksum = 256 # Force bad checksum
if self.bit >= 40: # Message complete
self.bit = 40
elif self.bit >= 32: # In checksum byte
self.checksum = (self.checksum << 1) + val
if self.bit == 39:
# 40th bit received
self.pi.set_watchdog(self.gpio, 0)
total = self.humidity + self.temperature
# is checksum ok ?
if not (total & 255) == self.checksum:
raise
elif 16 <= self.bit < 24: # in temperature byte
self.temperature = (self.temperature << 1) + val
elif 0 <= self.bit < 8: # in humidity byte
self.humidity = (self.humidity << 1) + val
else: # skip header bits
pass
self.bit += 1
def _edge_FALL(self, tick, diff):
"""
Handle Fall signal.
"""
self.high_tick = tick
if diff <= 250000:
return
self.bit = -2
self.checksum = 0
self.temperature = 0
self.humidity = 0
def _edge_EITHER(self, tick, diff):
"""
Handle Either signal.
"""
self.pi.set_watchdog(self.gpio, 0)
def read(self):
"""
Start reading over DHT11 sensor.
"""
self.pi.write(self.gpio, pigpio.LOW)
time.sleep(0.017) # 17 ms
self.pi.set_mode(self.gpio, pigpio.INPUT)
self.pi.set_watchdog(self.gpio, 200)
time.sleep(0.2)
def close(self):
"""
Stop reading sensor, remove callbacks.
"""
self.pi.set_watchdog(self.gpio, 0)
if self.either_edge_cb:
self.either_edge_cb.cancel()
self.either_edge_cb = None
def __iter__(self):
"""
Support the iterator protocol.
"""
return self
def __next__(self):
"""
Call the read method and return temperature and humidity informations.
"""
self.read()
response = {"humidity": self.humidity, "temperature": self.temperature}
return response
if __name__ == "__main__":
import sys
args = sys.argv
pin = int(args[1])
pi = pigpio.pi()
sensor = DHT11(pi, pin)
for d in sensor:
# print("temperature: {}".format(d["temperature"]))
# print("humidity: {}".format(d["humidity"]))
print(
'{"temperature":'
+ str(d["temperature"])
+ ',"humidity":'
+ str(d["humidity"])
+ "}",
flush=True,
)
break
# time.sleep(1)
sensor.close()

View File

@ -1,71 +0,0 @@
Blockly.Blocks['ugj_dht11'] = {
init: function () {
this.appendValueInput("pin")
.setCheck("Number")
.appendField("GPIO");
this.appendDummyInput()
.appendField("の DHT11 センサーの値を取得");
this.setInputsInline(true);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip("");
this.setHelpUrl("気温・湿度センサーDHT11で、気温摂氏、湿度を計測します。計測値は計測値ブロックで参照します。");
this.setStyle('sensor_blocks');
}
};
Blockly.JavaScript['ugj_dht11'] = function (block) {
var value_pin = Blockly.JavaScript.valueToCode(block, 'pin', Blockly.JavaScript.ORDER_ATOMIC);
let pypath = apptool.path.join(apptool.blocks_dir, 'sensors', 'dht11', 'dht11.py');
var code = `let _th = require('child_process').spawnSync('python3', ['${pypath}', '${value_pin}'], {timeout: 5000}).stdout.toString();
let _dhtdata = JSON.parse(_th);`;
// let _dht11data[0] =
// console.log('t=' + obj.temperature);
// console.log('h=' + obj.humidity);
return code;
};
Blockly.Blocks['ugj_dht11_data'] = {
init: function () {
this.appendDummyInput()
.appendField(new Blockly.FieldDropdown([["気温", "temperature"], ["湿度", "humidity"]]), "th");
this.setInputsInline(true);
this.setOutput(true, null);
this.setStyle('sensor_blocks');
this.setTooltip("DHT11 の計測値を返します。");
this.setHelpUrl("");
}
};
Blockly.JavaScript['ugj_dht11_data'] = function (block) {
var dropdown_th = block.getFieldValue('th');
var code = `_dhtdata.${dropdown_th}`;
return [code, Blockly.JavaScript.ORDER_ATOMIC];
};
flyout_contents = flyout_contents.concat([
{
"kind": "label",
"text": "温湿度センサー DHT11",
"web-line": "4.0",
"web-line-width": "200"
},
{
"kind": "block",
"type": "ugj_dht11",
"inputs": {
"pin": {
"shadow": {
"type": "math_number",
"fields": {
"NUM": "8"
}
}
}
}
},
{
"kind": "block",
"type": "ugj_dht11_data",
"fields": {
"th": "temperature"
}
}
]);

View File

@ -30,7 +30,5 @@ registerCategory('sensors', [ // サブカテゴリファイル名
"paj7620.js", "paj7620.js",
"bme280.js", "bme280.js",
"ssd1306.js", "ssd1306.js",
// "dht11", "z-line.js" // フライアウト下端の不可視ライン。フライアウトのアップデートをここで行っているので変更・削除に注意!
// "pico_slave",
"z-line.js" // フライアウト下端の不可視ライン。スクリプトにカテゴリ名を含むので注意
]); ]);

View File

@ -1,66 +0,0 @@
Blockly.Blocks['oc_i2cslave'] = {
init: function () {
this.appendValueInput("i2c_addr")
.setCheck("Number")
.appendField("PICOスレーブI2Cアドレス");
this.appendDummyInput()
.appendField(new Blockly.FieldVariable("データ"), "data")
.appendField("を受け取ったら");
this.appendStatementInput("do")
.setCheck(null);
this.setInputsInline(false);
this.setPreviousStatement(true, null);
this.setTooltip("Raspberry Pi Pico及びその互換機を I2Cスレーブ化します。受信データは1バイトデータです。i2c_slave.py が必要です。");
this.setHelpUrl("");
this.setStyle('gpio_blocks');
}
};
Blockly.Python['oc_i2cslave'] = function (block) {
var value_i2c_addr = Blockly.Python.valueToCode(block, 'i2c_addr', Blockly.Python.ORDER_ATOMIC);
var variable_data = Blockly.Python.nameDB_.getName(block.getFieldValue('data'), Blockly.Names.NameType.VARIABLE);
var statements_do = Blockly.Python.statementToCode(block, 'do');
Blockly.Python.provideFunction_(
'import_i2cslave', ['from i2cSlave import i2c_slave']
);
var code = `_i2cs = i2c_slave(0,sda=0,scl=1,slaveAddress=${value_i2c_addr})
while True:
${variable_data} = int(_i2cs.get())
${statements_do}
`;
return code;
};
flyout_contents = flyout_contents.concat([
{
"kind": "label",
"text": "RPi Pico I2Cスレーブ化",
"web-line": "4.0",
"web-line-width": "200"
}, {
"kind": "block",
"type": "oc_i2cslave",
"fields": {
"data": {
"name": "データ"
}
},
"inputs": {
"i2c_addr": {
"shadow": {
"type": "ugj_hextodec",
"inputs": {
"hex": {
"shadow": {
"type": "text",
"fields": {
"TEXT": "41"
}
}
}
}
}
}
}
}
])

View File

@ -51,18 +51,12 @@ Blockly.defineBlocksWithJsonArray([{
"helpUrl": "", "helpUrl": "",
"style": "sensor_blocks" "style": "sensor_blocks"
}]); }]);
Blockly.JavaScript['ugj_grideye_init'] = function (block) { javascript.javascriptGenerator.forBlock['ugj_grideye_init'] = function (block, generator) {
var dropdown_addr = block.getFieldValue('addr'); var dropdown_addr = block.getFieldValue('addr');
// Blockly.JavaScript.provideFunction_(
// 'require_gpio', [`const _pi = require('` + apptool.gpio_lib + `');`]
// );
// let modpath = apptool.path.join(apptool.blocks_dir, 'sensors', 'amg8833', `AMG8833x.js`);
Blockly.JavaScript.provideFunction_( Blockly.JavaScript.provideFunction_(
'require_amg8833', [`const _amg8833 = require('@ocoge/amg8833');`] 'require_amg8833', [`const _amg8833 = require('@ocoge/amg8833');`]
// 'require_amg8833', [`const _amg8833 = require('${modpath}');`]
); );
var code = `await _amg8833.init(_rg, ${apptool.i2c_bus}, ${dropdown_addr});\n`; var code = `await _amg8833.init(_rg, ${apptool.i2c_bus}, ${dropdown_addr});\n`;
// var code = `await _amg8833.init(${apptool.i2c_bus}, ${dropdown_addr}, window.addEventListener);\n`;
return code;// return code;//
}; };
/********************** */ /********************** */
@ -76,7 +70,7 @@ Blockly.defineBlocksWithJsonArray([{
"helpUrl": "", "helpUrl": "",
"style": "sensor_blocks" "style": "sensor_blocks"
}]); }]);
Blockly.JavaScript['ugj_grideye_thermistor'] = function (block) { javascript.javascriptGenerator.forBlock['ugj_grideye_thermistor'] = function (block, generator) {
var code = `await _amg8833.read_thermistor()`; var code = `await _amg8833.read_thermistor()`;
return [code, Blockly.JavaScript.ORDER_NONE]; return [code, Blockly.JavaScript.ORDER_NONE];
}; };
@ -93,7 +87,7 @@ Blockly.defineBlocksWithJsonArray([{
"helpUrl": "", "helpUrl": "",
"style": "sensor_blocks" "style": "sensor_blocks"
}]); }]);
Blockly.JavaScript['ugj_grideye_read'] = function (block) { javascript.javascriptGenerator.forBlock['ugj_grideye_read'] = function (block, generator) {
var code = 'await _amg8833.read_temp_array()'; var code = 'await _amg8833.read_temp_array()';
return [code, Blockly.JavaScript.ORDER_ATOMIC]; return [code, Blockly.JavaScript.ORDER_ATOMIC];
}; };
@ -110,7 +104,7 @@ Blockly.defineBlocksWithJsonArray([{
"helpUrl": "", "helpUrl": "",
"style": "sensor_blocks" "style": "sensor_blocks"
}]); }]);
Blockly.JavaScript['ugj_grideye_stop'] = function (block) { javascript.javascriptGenerator.forBlock['ugj_grideye_stop'] = function (block, generator) {
var code = 'await _amg8833.stop();\n'; var code = 'await _amg8833.stop();\n';
return code; return code;
}; };
@ -129,7 +123,7 @@ Blockly.defineBlocksWithJsonArray([{
"helpUrl": "", "helpUrl": "",
"style": "multimedia_blocks" "style": "multimedia_blocks"
}]); }]);
Blockly.JavaScript['ugj_grideye_canvas_create'] = function (block) { javascript.javascriptGenerator.forBlock['ugj_grideye_canvas_create'] = function (block, generator) {
var code = `let _grideye_canvas = document.createElement('canvas'); var code = `let _grideye_canvas = document.createElement('canvas');
_grideye_canvas.setAttribute('width', 8); _grideye_canvas.setAttribute('width', 8);
_grideye_canvas.setAttribute('height', 8); _grideye_canvas.setAttribute('height', 8);
@ -190,7 +184,7 @@ Blockly.defineBlocksWithJsonArray([{
"helpUrl": "", "helpUrl": "",
"style": "multimedia_blocks" "style": "multimedia_blocks"
}]); }]);
Blockly.JavaScript['ugj_draw_grideyedata'] = function (block) { javascript.javascriptGenerator.forBlock['ugj_draw_grideyedata'] = function (block, generator) {
var value_amg8833data = Blockly.JavaScript.valueToCode(block, 'amg8833data', Blockly.JavaScript.ORDER_ATOMIC); var value_amg8833data = Blockly.JavaScript.valueToCode(block, 'amg8833data', Blockly.JavaScript.ORDER_ATOMIC);
var colour_color_high = block.getFieldValue('color_high'); var colour_color_high = block.getFieldValue('color_high');
var value_temp_high = Blockly.JavaScript.valueToCode(block, 'temp_high', Blockly.JavaScript.ORDER_ATOMIC); var value_temp_high = Blockly.JavaScript.valueToCode(block, 'temp_high', Blockly.JavaScript.ORDER_ATOMIC);
@ -241,7 +235,7 @@ Blockly.defineBlocksWithJsonArray([{
"helpUrl": "", "helpUrl": "",
"style": "multimedia_blocks" "style": "multimedia_blocks"
}]); }]);
Blockly.JavaScript['ugj_teachable_machine'] = function (block) { javascript.javascriptGenerator.forBlock['ugj_teachable_machine'] = function (block, generator) {
Blockly.JavaScript.provideFunction_( Blockly.JavaScript.provideFunction_(
'require_ts', [`const _tf = require('@tensorflow/tfjs-node');`] 'require_ts', [`const _tf = require('@tensorflow/tfjs-node');`]
); );
@ -269,7 +263,7 @@ Blockly.defineBlocksWithJsonArray([{
"helpUrl": "", "helpUrl": "",
"style": "multimedia_blocks" "style": "multimedia_blocks"
}]); }]);
Blockly.JavaScript['ugj_grideye_predict_class'] = function (block) { javascript.javascriptGenerator.forBlock['ugj_grideye_predict_class'] = function (block, generator) {
var functionName = Blockly.JavaScript.provideFunction_( // left output にするための関数化 var functionName = Blockly.JavaScript.provideFunction_( // left output にするための関数化
'_predictClass', '_predictClass',
[ [
@ -307,7 +301,7 @@ Blockly.defineBlocksWithJsonArray([{
"helpUrl": "", "helpUrl": "",
"style": "multimedia_blocks" "style": "multimedia_blocks"
}]); }]);
Blockly.JavaScript['ugj_grideye_add_example'] = function (block) { javascript.javascriptGenerator.forBlock['ugj_grideye_add_example'] = function (block, generator) {
var value_class_id = Blockly.JavaScript.valueToCode(block, 'class_id', Blockly.JavaScript.ORDER_ATOMIC); var value_class_id = Blockly.JavaScript.valueToCode(block, 'class_id', Blockly.JavaScript.ORDER_ATOMIC);
var code = `_classifier.addExample (_net.infer(_grideye_canvas, true), ${value_class_id});`; var code = `_classifier.addExample (_net.infer(_grideye_canvas, true), ${value_class_id});`;
return code; return code;
@ -323,7 +317,7 @@ Blockly.defineBlocksWithJsonArray([{
"helpUrl": "", "helpUrl": "",
"style": "multimedia_blocks" "style": "multimedia_blocks"
}]); }]);
Blockly.JavaScript['ugj_tensorset_stringify'] = function (block) { javascript.javascriptGenerator.forBlock['ugj_tensorset_stringify'] = function (block, generator) {
var code = `JSON.stringify( Object.entries(_classifier.getClassifierDataset()).map(([label, data])=>[label, Array.from(data.dataSync()), data.shape]) )`; var code = `JSON.stringify( Object.entries(_classifier.getClassifierDataset()).map(([label, data])=>[label, Array.from(data.dataSync()), data.shape]) )`;
return [code, Blockly.JavaScript.ORDER_NONE]; return [code, Blockly.JavaScript.ORDER_NONE];
}; };
@ -346,7 +340,7 @@ Blockly.defineBlocksWithJsonArray([{
"helpUrl": "", "helpUrl": "",
"style": "multimedia_blocks" "style": "multimedia_blocks"
}]); }]);
Blockly.JavaScript['ugj_tensorset_parse'] = function (block) { javascript.javascriptGenerator.forBlock['ugj_tensorset_parse'] = function (block, generator) {
var value_class_data_json = Blockly.JavaScript.valueToCode(block, 'class_data_json', Blockly.JavaScript.ORDER_ATOMIC); var value_class_data_json = Blockly.JavaScript.valueToCode(block, 'class_data_json', Blockly.JavaScript.ORDER_ATOMIC);
var code = `_classifier.setClassifierDataset( Object.fromEntries( JSON.parse(${value_class_data_json}).map(([label, data, shape])=>[label, _tf.tensor(data, shape)]) ) );`; var code = `_classifier.setClassifierDataset( Object.fromEntries( JSON.parse(${value_class_data_json}).map(([label, data, shape])=>[label, _tf.tensor(data, shape)]) ) );`;
return code; return code;
@ -372,7 +366,7 @@ Blockly.defineBlocksWithJsonArray([{
"helpUrl": "", "helpUrl": "",
"style": "math_blocks" "style": "math_blocks"
}]); }]);
Blockly.JavaScript['ugj_temp'] = function (block) { javascript.javascriptGenerator.forBlock['ugj_temp'] = function (block, generator) {
var number_temp = block.getFieldValue('temp'); var number_temp = block.getFieldValue('temp');
var code = `${number_temp}`; var code = `${number_temp}`;
return [code, Blockly.JavaScript.ORDER_NONE]; return [code, Blockly.JavaScript.ORDER_NONE];

View File

@ -15,16 +15,10 @@ Blockly.Blocks['ugj_bme280'] = {
this.setHelpUrl(""); this.setHelpUrl("");
} }
}; };
Blockly.JavaScript['ugj_bme280'] = function (block) { javascript.javascriptGenerator.forBlock['ugj_bme280'] = function (block, generator) {
var dropdown_addr = block.getFieldValue('addr'); var dropdown_addr = block.getFieldValue('addr');
// Blockly.JavaScript.provideFunction_(
// 'require_gpio', [`const _pi = require('` + apptool.gpio_lib + `');`]
// );
// let modpath = apptool.path.join(apptool.blocks_dir, 'sensors', 'bme280', 'BME280x.js');
// let modpath = apptool.path.join(apptool.blocks_dir, 'sensors', 'bme280', `BME280x.js`);
Blockly.JavaScript.provideFunction_( Blockly.JavaScript.provideFunction_(
'require_bme280', [`const _bme280 = require('@ocoge/bme280');`] 'require_bme280', [`const _bme280 = require('@ocoge/bme280');`]
// 'require_bme280', [`const _bme280 = require('${modpath}');`]
); );
var code = `const options = { var code = `const options = {
i2cBusNo: ${apptool.i2c_bus}, i2cBusNo: ${apptool.i2c_bus},
@ -51,7 +45,7 @@ Blockly.Blocks['ugj_bme280_data'] = {
this.setHelpUrl(""); this.setHelpUrl("");
} }
}; };
Blockly.JavaScript['ugj_bme280_data'] = function (block) { javascript.javascriptGenerator.forBlock['ugj_bme280_data'] = function (block, generator) {
var dropdown_thp = block.getFieldValue('thp'); var dropdown_thp = block.getFieldValue('thp');
var code = `_bmedata[${dropdown_thp}]`; var code = `_bmedata[${dropdown_thp}]`;
return [code, Blockly.JavaScript.ORDER_ATOMIC]; return [code, Blockly.JavaScript.ORDER_ATOMIC];

View File

@ -30,15 +30,10 @@ Blockly.Blocks['ugj_gesture_init'] = {
this.jsonInit(ugjGestureInitDefinition); this.jsonInit(ugjGestureInitDefinition);
} }
}; };
Blockly.JavaScript['ugj_gesture_init'] = function (block) { javascript.javascriptGenerator.forBlock['ugj_gesture_init'] = function (block, generator) {
var value_i2c_addr = Blockly.JavaScript.valueToCode(block, 'i2c_addr', Blockly.JavaScript.ORDER_ATOMIC); var value_i2c_addr = Blockly.JavaScript.valueToCode(block, 'i2c_addr', Blockly.JavaScript.ORDER_ATOMIC);
// Blockly.JavaScript.provideFunction_(
// 'require_gpio', [`const _pi = require('` + apptool.gpio_lib + `');`]
// );
// let modpath = apptool.path.join(apptool.blocks_dir, 'sensors', 'paj7620', 'PAJ7620x.js');
Blockly.JavaScript.provideFunction_( Blockly.JavaScript.provideFunction_(
'require_paj7620', [`const _paj7620 = require('@ocoge/paj7620');`] 'require_paj7620', [`const _paj7620 = require('@ocoge/paj7620');`]
// 'require_paj7620', [`const _paj7620 = require('${modpath}');`]
); );
var code = `await _paj7620.init(_rg, ${apptool.i2c_bus}, ${value_i2c_addr}); var code = `await _paj7620.init(_rg, ${apptool.i2c_bus}, ${value_i2c_addr});
`; `;
@ -62,7 +57,7 @@ Blockly.Blocks['ugj_gesture_read'] = {
this.jsonInit(ugjGestureReadDefinition); this.jsonInit(ugjGestureReadDefinition);
} }
}; };
Blockly.JavaScript['ugj_gesture_read'] = function (block) { javascript.javascriptGenerator.forBlock['ugj_gesture_read'] = function (block, generator) {
var code = 'await _paj7620.return_gesture()'; var code = 'await _paj7620.return_gesture()';
return [code, Blockly.JavaScript.ORDER_ATOMIC]; return [code, Blockly.JavaScript.ORDER_ATOMIC];
}; };
@ -84,7 +79,7 @@ Blockly.Blocks['ugj_gesture_stop'] = {
this.jsonInit(ugjGestureStopDefinition); this.jsonInit(ugjGestureStopDefinition);
} }
}; };
Blockly.JavaScript['ugj_gesture_stop'] = function (block) { javascript.javascriptGenerator.forBlock['ugj_gesture_stop'] = function (block, generator) {
var code = 'await _paj7620.stop();\n'; var code = 'await _paj7620.stop();\n';
return code; return code;
}; };

View File

@ -915,32 +915,6 @@
</shadow> </shadow>
</value> </value>
</block> </block>
<block type="ugj_child_irrecord">
<value name="gpio">
<shadow type="math_number">
<field name="NUM">23</field>
</shadow>
</value>
</block>
<block type="ugj_child_irplayback">
<value name="gpio">
<shadow type="math_number">
<field name="NUM">22</field>
</shadow>
</value>
<value name="signal">
<shadow type="text">
<field name="TEXT"></field>
</shadow>
</value>
</block>
<block type="ugj_child_irrcvr">
<value name="gpio">
<shadow type="math_number">
<field name="NUM">23</field>
</shadow>
</value>
</block>
<block type="ugj_child_fswebcam"> <block type="ugj_child_fswebcam">
<value name="filename"> <value name="filename">
<shadow type="text"> <shadow type="text">

View File

@ -1,515 +0,0 @@
#!/usr/bin/env python
# irrp.py
# 2015-12-21
# Public Domain
"""
A utility to record and then playback IR remote control codes.
To record use
./irrp.py -r -g4 -fcodes 1 2 3 4 5 6
where
-r record
-g the GPIO connected to the IR receiver
-f the file to store the codes
and 1 2 3 4 5 6 is a list of codes to record.
To playback use
./irrp.py -p -g17 -fcodes 2 3 4
where
-p playback
-g the GPIO connected to the IR transmitter
-f the file storing the codes to transmit
and 2 3 4 is a list of codes to transmit.
OPTIONS
-r record
-p playback
-g GPIO (receiver for record, transmitter for playback)
-f file
id1 id2 id3 list of ids to record or transmit
RECORD
--glitch ignore edges shorter than glitch microseconds, default 100 us
--post expect post milliseconds of silence after code, default 15 ms
--pre expect pre milliseconds of silence before code, default 200 ms
--short reject codes with less than short pulses, default 10
--tolerance consider pulses the same if within tolerance percent, default 15
--no-confirm don't require a code to be repeated during record
TRANSMIT
--freq IR carrier frequency, default 38 kHz
--gap gap in milliseconds between transmitted codes, default 100 ms
"""
import time
import json
import os
import argparse
import pigpio # http://abyz.co.uk/rpi/pigpio/python.html
p = argparse.ArgumentParser()
g = p.add_mutually_exclusive_group(required=True)
g.add_argument("-p", "--play", help="play keys", action="store_true")
g.add_argument("-r", "--record", help="record keys", action="store_true")
p.add_argument("-g", "--gpio", help="GPIO for RX/TX", required=True, type=int)
# p.add_argument("-f", "--file", help="Filename", required=True)
p.add_argument("--irdata", help="IR Data")
p.add_argument('id', nargs='+', type=str, help='IR codes')
p.add_argument("--freq", help="frequency kHz", type=float, default=38.0)
p.add_argument("--gap", help="key gap ms", type=int, default=100)
p.add_argument("--glitch", help="glitch us", type=int, default=100)
p.add_argument("--post", help="postamble ms", type=int, default=15)
p.add_argument("--pre", help="preamble ms", type=int, default=200)
p.add_argument("--short", help="short code length", type=int, default=10)
p.add_argument("--tolerance", help="tolerance percent", type=int, default=15)
p.add_argument("-v", "--verbose", help="Be verbose", action="store_true")
p.add_argument("--no-confirm", help="No confirm needed", action="store_true")
args = p.parse_args()
GPIO = args.gpio
# FILE = args.file
IRDATA = args.irdata
GLITCH = args.glitch
PRE_MS = args.pre
POST_MS = args.post
FREQ = args.freq
VERBOSE = args.verbose
SHORT = args.short
GAP_MS = args.gap
NO_CONFIRM = args.no_confirm
TOLERANCE = args.tolerance
POST_US = POST_MS * 1000
PRE_US = PRE_MS * 1000
GAP_S = GAP_MS / 1000.0
CONFIRM = not NO_CONFIRM
TOLER_MIN = (100 - TOLERANCE) / 100.0
TOLER_MAX = (100 + TOLERANCE) / 100.0
last_tick = 0
in_code = False
code = []
fetching_code = False
def backup(f):
"""
f -> f.bak -> f.bak1 -> f.bak2
"""
try:
os.rename(os.path.realpath(f)+".bak1", os.path.realpath(f)+".bak2")
except:
pass
try:
os.rename(os.path.realpath(f)+".bak", os.path.realpath(f)+".bak1")
except:
pass
try:
os.rename(os.path.realpath(f), os.path.realpath(f)+".bak")
except:
pass
def carrier(gpio, frequency, micros):
"""
Generate carrier square wave.
"""
wf = []
cycle = 1000.0 / frequency
cycles = int(round(micros/cycle))
on = int(round(cycle / 2.0))
sofar = 0
for c in range(cycles):
target = int(round((c+1)*cycle))
sofar += on
off = target - sofar
sofar += off
wf.append(pigpio.pulse(1<<gpio, 0, on))
wf.append(pigpio.pulse(0, 1<<gpio, off))
return wf
def normalise(c):
"""
Typically a code will be made up of two or three distinct
marks (carrier) and spaces (no carrier) of different lengths.
Because of transmission and reception errors those pulses
which should all be x micros long will have a variance around x.
This function identifies the distinct pulses and takes the
average of the lengths making up each distinct pulse. Marks
and spaces are processed separately.
This makes the eventual generation of waves much more efficient.
Input
M S M S M S M S M S M
9000 4500 600 540 620 560 590 1660 620 1690 615
Distinct marks
9000 average 9000
600 620 590 620 615 average 609
Distinct spaces
4500 average 4500
540 560 average 550
1660 1690 average 1675
Output
M S M S M S M S M S M
9000 4500 609 550 609 550 609 1675 609 1675 609
"""
if VERBOSE:
print("before normalise", c, flush=True)
entries = len(c)
p = [0]*entries # Set all entries not processed.
for i in range(entries):
if not p[i]: # Not processed?
v = c[i]
tot = v
similar = 1.0
# Find all pulses with similar lengths to the start pulse.
for j in range(i+2, entries, 2):
if not p[j]: # Unprocessed.
if (c[j]*TOLER_MIN) < v < (c[j]*TOLER_MAX): # Similar.
tot = tot + c[j]
similar += 1.0
# Calculate the average pulse length.
newv = round(tot / similar, 2)
c[i] = newv
# Set all similar pulses to the average value.
for j in range(i+2, entries, 2):
if not p[j]: # Unprocessed.
if (c[j]*TOLER_MIN) < v < (c[j]*TOLER_MAX): # Similar.
c[j] = newv
p[j] = 1
if VERBOSE:
print("after normalise", c, flush=True)
def compare(p1, p2):
"""
Check that both recodings correspond in pulse length to within
TOLERANCE%. If they do average the two recordings pulse lengths.
Input
M S M S M S M S M S M
1: 9000 4500 600 560 600 560 600 1700 600 1700 600
2: 9020 4570 590 550 590 550 590 1640 590 1640 590
Output
A: 9010 4535 595 555 595 555 595 1670 595 1670 595
"""
if len(p1) != len(p2):
return False
for i in range(len(p1)):
v = p1[i] / p2[i]
if (v < TOLER_MIN) or (v > TOLER_MAX):
return False
for i in range(len(p1)):
p1[i] = int(round((p1[i]+p2[i])/2.0))
if VERBOSE:
print("after compare", p1, flush=True)
return True
def tidy_mark_space(records, base):
ms = {}
# Find all the unique marks (base=0) or spaces (base=1)
# and count the number of times they appear,
for rec in records:
rl = len(records[rec])
for i in range(base, rl, 2):
if records[rec][i] in ms:
ms[records[rec][i]] += 1
else:
ms[records[rec][i]] = 1
if VERBOSE:
print("t_m_s A", ms, flush=True)
v = None
for plen in sorted(ms):
# Now go through in order, shortest first, and collapse
# pulses which are the same within a tolerance to the
# same value. The value is the weighted average of the
# occurences.
#
# E.g. 500x20 550x30 600x30 1000x10 1100x10 1700x5 1750x5
#
# becomes 556(x80) 1050(x20) 1725(x10)
#
if v == None:
e = [plen]
v = plen
tot = plen * ms[plen]
similar = ms[plen]
elif plen < (v*TOLER_MAX):
e.append(plen)
tot += (plen * ms[plen])
similar += ms[plen]
else:
v = int(round(tot/float(similar)))
# set all previous to v
for i in e:
ms[i] = v
e = [plen]
v = plen
tot = plen * ms[plen]
similar = ms[plen]
v = int(round(tot/float(similar)))
# set all previous to v
for i in e:
ms[i] = v
if VERBOSE:
print("t_m_s B", ms, flush=True)
for rec in records:
rl = len(records[rec])
for i in range(base, rl, 2):
records[rec][i] = ms[records[rec][i]]
def tidy(records):
tidy_mark_space(records, 0) # Marks.
tidy_mark_space(records, 1) # Spaces.
def end_of_code():
global code, fetching_code
if len(code) > SHORT:
normalise(code)
fetching_code = False
else:
code = []
print("Short code, probably a repeat, try again", flush=True)
def cbf(gpio, level, tick):
global last_tick, in_code, code, fetching_code
if level != pigpio.TIMEOUT:
edge = pigpio.tickDiff(last_tick, tick)
last_tick = tick
if fetching_code:
if (edge > PRE_US) and (not in_code): # Start of a code.
in_code = True
pi.set_watchdog(GPIO, POST_MS) # Start watchdog.
elif (edge > POST_US) and in_code: # End of a code.
in_code = False
pi.set_watchdog(GPIO, 0) # Cancel watchdog.
end_of_code()
elif in_code:
code.append(edge)
else:
pi.set_watchdog(GPIO, 0) # Cancel watchdog.
if in_code:
in_code = False
end_of_code()
pi = pigpio.pi() # Connect to Pi.
if not pi.connected:
exit(0)
if args.record: # Record.
# try:
# f = open(FILE, "r")
# records = json.load(f)
# f.close()
# except:
# records = {}
records = {}
pi.set_mode(GPIO, pigpio.INPUT) # IR RX connected to this GPIO.
pi.set_glitch_filter(GPIO, GLITCH) # Ignore glitches.
cb = pi.callback(GPIO, pigpio.EITHER_EDGE, cbf)
# Process each id
print("読み取り開始:", flush=True)
for arg in args.id:
print("リモコンのボタンを押してください。", flush=True)
code = []
fetching_code = True
while fetching_code:
time.sleep(0.1)
print("OK", flush=True)
time.sleep(0.5)
if CONFIRM:
press_1 = code[:]
done = False
tries = 0
while not done:
print("確認のためもう一度同じボタンを押してください。", flush=True)
code = []
fetching_code = True
while fetching_code:
time.sleep(0.1)
press_2 = code[:]
the_same = compare(press_1, press_2)
if the_same:
done = True
records[arg] = press_1[:]
print("OK", flush=True)
time.sleep(0.5)
else:
tries += 1
if tries <= 3:
print("信号が一致しません。", flush=True)
else:
print("信号が一致しませんでした。終了します。", flush=True)
done = True
time.sleep(0.5)
else: # No confirm.
records[arg] = code[:]
pi.set_glitch_filter(GPIO, 0) # Cancel glitch filter.
pi.set_watchdog(GPIO, 0) # Cancel watchdog.
tidy(records)
# backup(FILE)
# f = open(FILE, "w")
# f.write(json.dumps(records, sort_keys=True).replace("],", "],\n")+"\n")
# f.close()
# print('\n', flush=True)
print(json.dumps(records), flush=True)
else: # Playback.
# try:
# f = open(FILE, "r")
# except:
# print("Can't open: {}".format(FILE))
# exit(0)
# print(FILE, flush=True)
records = json.loads(IRDATA)
# records = json.loads(FILE)
# print(records, flush=True)
# f.close()
pi.set_mode(GPIO, pigpio.OUTPUT) # IR TX connected to this GPIO.
pi.wave_add_new()
emit_time = time.time()
if VERBOSE:
print("送信中", flush=True)
for arg in args.id:
if arg in records:
code = records[arg]
# Create wave
marks_wid = {}
spaces_wid = {}
wave = [0]*len(code)
for i in range(0, len(code)):
ci = code[i]
if i & 1: # Space
if ci not in spaces_wid:
pi.wave_add_generic([pigpio.pulse(0, 0, ci)])
spaces_wid[ci] = pi.wave_create()
wave[i] = spaces_wid[ci]
else: # Mark
if ci not in marks_wid:
wf = carrier(GPIO, FREQ, ci)
pi.wave_add_generic(wf)
marks_wid[ci] = pi.wave_create()
wave[i] = marks_wid[ci]
delay = emit_time - time.time()
if delay > 0.0:
time.sleep(delay)
pi.wave_chain(wave)
if VERBOSE:
print("key " + arg, flush=True)
while pi.wave_tx_busy():
time.sleep(0.002)
emit_time = time.time() + GAP_S
for i in marks_wid:
pi.wave_delete(marks_wid[i])
marks_wid = {}
for i in spaces_wid:
pi.wave_delete(spaces_wid[i])
spaces_wid = {}
print("Id: {}".format(arg), flush=True)
else:
print("Id {} not found".format(arg), flush=True)
pi.stop() # Disconnect from Pi.

View File

@ -1,47 +0,0 @@
# -*- coding: utf-8 -*-
import sys
import Adafruit_SSD1306
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
# Settings
FONT_SIZE = 12
LINE_SPACING = 4
args = sys.argv
linenum = int(args[1]) # 0 origin
if linenum >= 0:
text = args[2]
RST = 24
disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST)
disp.begin()
if linenum < 0:
disp.clear()
disp.display()
exit()
width = disp.width
height = disp.height
image = Image.new('1', (width, height))
draw = ImageDraw.Draw(image)
#draw.rectangle((0, 0, width, height), outline=0, fill=0)
font = ImageFont.truetype(
'/usr/share/fonts/truetype/dejavu/DejaVuSerif.ttf', 12)
LINE_HEIGHT = FONT_SIZE + LINE_SPACING
x = 0
y = linenum * LINE_HEIGHT
draw.rectangle((x, y, width, y+LINE_HEIGHT), outline=0, fill=0) # 行消去
draw.text((0, y), text, font=font, fill=255)
disp.image(image)
disp.display()

View File

@ -1,24 +1,13 @@
'use strict'; 'use strict';
const err_msg = 'AMG8833 is already opened. Please close old connection to use new one.'; const err_msg = 'AMG8833 is already opened. Please close old connection to use new one.';
// const pig = require(`${apptool.gpio_lib}`);
// let pi = -1;
let rg; let rg;
let i2c_hand = -1; let i2c_hand = -1;
exports.init = async (_rg, i2c_bus, i2c_addr, wael = null) => { exports.init = async (_rg, i2c_bus, i2c_addr, wael = null) => {
// if (wael !== null) {
// wael('beforeunload', async () => {
// await exports.stop();
// });
// }
// if (pi >= 0) { throw new Error(err_msg); return; }
// pi = await pig._rgpiod_start('', '');
// console.log('pi=' + pi);
rg = _rg; rg = _rg;
if (i2c_hand >= 0) { throw new Error(err_msg); return; } if (i2c_hand >= 0) { throw new Error(err_msg); return; }
i2c_hand = await rg.i2c_open(i2c_bus, i2c_addr, 0); i2c_hand = await rg.i2c_open(i2c_bus, i2c_addr, 0);
// i2c_hand = await pig._i2c_open(pi, i2c_bus, i2c_addr, 0);
console.log('i2c_hand=' + i2c_hand); console.log('i2c_hand=' + i2c_hand);
await rg.i2c_write_byte_data(i2c_hand, 0x00, 0x00); //Normal mode await rg.i2c_write_byte_data(i2c_hand, 0x00, 0x00); //Normal mode
await rg.i2c_write_byte_data(i2c_hand, 0x02, 0x00); //10FPS await rg.i2c_write_byte_data(i2c_hand, 0x02, 0x00); //10FPS
@ -47,10 +36,6 @@ exports.stop = async () => {
await rg.i2c_close(i2c_hand); await rg.i2c_close(i2c_hand);
i2c_hand = -1; i2c_hand = -1;
} }
// if (pi >= 0) {
// await pig._rgpiod_stop(pi);
// pi = -1;
// }
} }
/* /*

View File

@ -1,7 +1,5 @@
'use strict'; 'use strict';
// this.pig = null;
// this.pi = null;
this.rg = null; this.rg = null;
this.i2cBusNo = null; this.i2cBusNo = null;
@ -43,8 +41,6 @@ this.REGISTER_TEMP_DATA = 0xFA;
this.REGISTER_HUMIDITY_DATA = 0xFD; this.REGISTER_HUMIDITY_DATA = 0xFD;
exports.init = async (rg, options) => { exports.init = async (rg, options) => {
// this.pig = require(`${apptool.gpio_lib}`);
// this.pi = await this.rg.rgpiod_start('', '');
this.rg = rg; this.rg = rg;
this.i2cBusNo = (options && options.hasOwnProperty('i2cBusNo')) ? options.i2cBusNo : 1; this.i2cBusNo = (options && options.hasOwnProperty('i2cBusNo')) ? options.i2cBusNo : 1;
@ -98,8 +94,6 @@ exports.cancel = async () => {
if (this.i2cHand >= 0) { if (this.i2cHand >= 0) {
await this.rg.i2c_close(this.i2cHand); await this.rg.i2c_close(this.i2cHand);
this.i2cHand = null; this.i2cHand = null;
// await this.rg.rgpiod_stop(this.pi);
// this.pi = null;
} }
} }

View File

@ -461,10 +461,6 @@ exports.stop = async () => {
await rg.i2c_close(i2c_hand); await rg.i2c_close(i2c_hand);
i2c_hand = -1; i2c_hand = -1;
} }
// if (sbc >= 0) {
// await rg.rgpiod_stop(sbc);
// sbc = -1;
// }
} }
/* /*

View File

@ -147,6 +147,4 @@ module.exports.i2c_write_device_sync = (handle, data, count = -1) => {
// 終了処理 // 終了処理
module.exports.close_all_handle = async () => { module.exports.close_all_handle = async () => {
await module.exports.sbc_stop(); await module.exports.sbc_stop();
// await module.exports.serial_close();
// await module.exports.i2c_close();
} }

View File

@ -1,5 +1,5 @@
/** lgpio を Node.js から利用するモジュール ** */ /** lgpio を Node.js から利用するモジュール ** */
/** 関数名・書式は lgpio Python に準拠 ******************* */ /** 関数名・書式は rgpio Python に準拠 ******************* */
#include <napi.h> #include <napi.h>
#include <rgpio.h> #include <rgpio.h>

View File

@ -1,285 +0,0 @@
![npm version](http://img.shields.io/npm/v/oled-js.svg?style=flat) ![downloads over month](http://img.shields.io/npm/dm/oled-js.svg?style=flat)
OLED JS Pi over i2c-bus
========================
## What is this?
This is fork of package [`oled-js-pi`](https://github.com/kd7yva/oled-js-pi) that works thru `i2c-bus` package and not use package `i2c`.
A NodeJS driver for I2C/SPI compatible monochrome OLED screens; to be used on the Raspberry Pi! Works with 128 x 32, 128 x 64 and 96 x 16 sized screens, of the SSD1306 OLED/PLED Controller (read the [datasheet here](http://www.adafruit.com/datasheets/SSD1306.pdf)).
This based on the Blog Post and code by Suz Hinton - [Read her blog post about how OLED screens work](http://meow.noopkat.com/oled-js/)!
OLED screens are really cool - now you can control them with JavaScript!
## Install
If you haven't already, install [NodeJS](http://nodejs.org/).
`npm install oled-i2c-bus`
## I2C screens
Hook up I2C compatible oled to the Raspberry Pi. Pins: SDL and SCL
### I2C example
```javascript
var i2c = require('i2c-bus'),
i2cBus = i2c.openSync(1),
oled = require('oled-i2c-bus');
var opts = {
width: 128,
height: 64,
address: 0x3D
};
var oled = new oled(i2cBus, opts);
// do cool oled things here
```
### Wait, how do I find out the I2C address of my OLED screen?
Check your screen's documentation...
## Available methods
### clearDisplay
Fills the buffer with 'off' pixels (0x00). Optional bool argument specifies whether screen updates immediately with result. Default is true.
Usage:
```javascript
oled.clearDisplay();
```
### dimDisplay
Lowers the contrast on the display. This method takes one argument, a boolean. True for dimming, false to restore normal contrast.
Usage:
```javascript
oled.dimDisplay(true|false);
```
### invertDisplay
Inverts the pixels on the display. Black becomes white, white becomes black. This method takes one argument, a boolean. True for inverted state, false to restore normal pixel colors.
Usage:
```javascript
oled.invertDisplay(true|false);
```
### turnOffDisplay
Turns the display off.
Usage:
```javascript
oled.turnOffDisplay();
```
### turnOnDisplay
Turns the display on.
Usage:
```javascript
oled.turnOnDisplay();
```
### drawPixel
Draws a pixel at a specified position on the display. This method takes one argument: a multi-dimensional array containing either one or more sets of pixels.
Each pixel needs an x position, a y position, and a color. Colors can be specified as either 0 for 'off' or black, and 1 or 255 for 'on' or white.
Optional bool as last argument specifies whether screen updates immediately with result. Default is true.
Usage:
```javascript
// draws 4 white pixels total
// format: [x, y, color]
oled.drawPixel([
[128, 1, 1],
[128, 32, 1],
[128, 16, 1],
[64, 16, 1]
]);
```
### drawLine
Draws a one pixel wide line.
Arguments:
+ int **x0, y0** - start location of line
+ int **x1, y1** - end location of line
+ int **color** - can be specified as either 0 for 'off' or black, and 1 or 255 for 'on' or white.
Optional bool as last argument specifies whether screen updates immediately with result. Default is true.
Usage:
```javascript
// args: (x0, y0, x1, y1, color)
oled.drawLine(1, 1, 128, 32, 1);
```
### fillRect
Draws a filled rectangle.
Arguments:
+ int **x0, y0** - top left corner of rectangle
+ int **w, h** - width and height of rectangle
+ int **color** - can be specified as either 0 for 'off' or black, and 1 or 255 for 'on' or white.
Optional bool as last argument specifies whether screen updates immediately with result. Default is true.
Usage:
```javascript
// args: (x0, y0, x1, y1, color)
oled.fillRect(1, 1, 10, 20, 1);
```
### drawBitmap
Draws a bitmap using raw pixel data returned from an image parser. The image sourced must be monochrome, and indexed to only 2 colors. Resize the bitmap to your screen dimensions first. Using an image editor or ImageMagick might be required.
Optional bool as last argument specifies whether screen updates immediately with result. Default is true.
Tip: use a NodeJS image parser to get the pixel data, such as [pngparse](https://www.npmjs.org/package/pngparse). A demonstration of using this is below.
Example usage:
```
npm install pngparse
```
```javascript
var pngparse = require('pngparse');
pngparse.parseFile('indexed_file.png', function(err, image) {
oled.drawBitmap(image.data);
});
```
This method is provided as a primitive convenience. A better way to display images is to use NodeJS package [png-to-lcd](https://www.npmjs.org/package/png-to-lcd) instead. It's just as easy to use as drawBitmap, but is compatible with all image depths (lazy is good!). It will also auto-dither if you choose. You should still resize your image to your screen dimensions. This alternative method is covered below:
```
npm install png-to-lcd
```
```javascript
var pngtolcd = require('png-to-lcd');
pngtolcd('nyan-cat.png', true, function(err, bitmap) {
oled.buffer = bitmap;
oled.update();
});
```
### drawRGBAImage
Draw an RGBA coded image at specific coordinates. This only supports a monochrome
OLED so transparent pixels must be 100% transparent, off pixels should have an
RGB value of (0, 0, 0), and pixels with any color value will be considered on.
Use a library such as [pngjs](https://www.npmjs.com/package/pngjs) to read a png
file into the required rgba data structure.
Example:
```JavaScript
const fs = require('fs');
const PNG = require('pngjs').PNG;
const i2c = require('i2c-bus');
const oled = require('oled-i2c-bus');
var i2cBus = i2c.openSync(0);
var opts = {
width: 128,
height: 64,
address: 0x3C
};
var display = new oled(i2cBus, opts);
display.clearDisplay();
display.turnOnDisplay();
fs.createReadStream('./test.png')
.pipe(new PNG({ filterType: 4 }))
.on('parsed', function () {
setInterval(() => { drawImage(this) }, 1000);
});
function drawImage(image) {
let x = Math.floor(Math.random() * (display.WIDTH) - image.width / 2);
let y = Math.floor(Math.random() * (display.HEIGHT) - image.height / 2);
display.drawRGBAImage(image, x, y);
}
```
### startScroll
Scrolls the current display either left or right.
Arguments:
+ string **direction** - direction of scrolling. 'left' or 'right'
+ int **start** - starting row of scrolling area
+ int **stop** - end row of scrolling area
Usage:
```javascript
// args: (direction, start, stop)
oled.startscroll('left', 0, 15); // this will scroll an entire 128 x 32 screen
```
### stopScroll
Stops all current scrolling behaviour.
Usage:
```javascript
oled.stopscroll();
```
### setCursor
Sets the x and y position of 'cursor', when about to write text. This effectively helps tell the display where to start typing when writeString() method is called.
Call setCursor just before writeString().
Usage:
```javascript
// sets cursor to x = 1, y = 1
oled.setCursor(1, 1);
```
### writeString
Writes a string of text to the display.
Call setCursor() just before, if you need to set starting text position.
Arguments:
+ obj **font** - font object in JSON format (see note below on sourcing a font)
+ int **size** - font size, as multiplier. Eg. 2 would double size, 3 would triple etc.
+ string **text** - the actual text you want to show on the display.
+ int **color** - color of text. Can be specified as either 0 for 'off' or black, and 1 or 255 for 'on' or white.
+ bool **wrapping** - true applies word wrapping at the screen limit, false for no wrapping. If a long string without spaces is supplied as the text, just letter wrapping will apply instead.
Optional bool as last argument specifies whether screen updates immediately with result. Default is true.
Before all of this text can happen, you need to load a font buffer for use. A good font to start with is NodeJS package [oled-font-5x7](https://www.npmjs.org/package/oled-font-5x7).
Usage:
```
npm install oled-font-5x7
```
```javascript
var font = require('oled-font-5x7');
// sets cursor to x = 1, y = 1
oled.setCursor(1, 1);
oled.writeString(font, 1, 'Cats and dogs are really cool animals, you know.', 1, true);
```
### update
Sends the entire buffer in its current state to the oled display, effectively syncing the two. This method generally does not need to be called, unless you're messing around with the framebuffer manually before you're ready to sync with the display. It's also needed if you're choosing not to draw on the screen immediately with the built in methods.
Usage:
```javascript
oled.update();
```

View File

@ -1,15 +0,0 @@
OLED JS Pi over i2c-bus
========================
## What is this directory?
This directory contains a working example of NodeJS, a (typically) ARM board (Orange Pi Zero), and a 128x64 I2C SSD1306 display.
## Install
```
npm install
cp ../oled.js node_modules/oled-i2c-bus/
node clock.js
```

View File

@ -1,25 +0,0 @@
{
"name": "examples",
"version": "1.0.0",
"description": "Testing OLED SSD1306 display with nodeJS",
"main": "clock.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/haraldkubota/oled-i2c-bus"
},
"keywords": [
"oled",
"i2c"
],
"author": "Harald Kubota",
"license": "MIT",
"dependencies": {
"i2c-bus": "^1.1.2",
"oled-font-5x7": "^1.0.0",
"oled-i2c-bus": "^1.0.11",
"pngjs": "^3.3.3"
}
}

View File

@ -1,39 +0,0 @@
/*
* rgba.js
* Display an RGBA image at random locations on a small I2C connected display
*
* 2018-08-19 v1.0 Bryan Nielsen
*/
"use strict";
const fs = require('fs');
const PNG = require('pngjs').PNG;
const i2c = require('i2c-bus');
const oled = require('../oled');// 'oled-i2c-bus');
var i2cBus = i2c.openSync(0);
var opts = {
width: 128,
height: 64,
address: 0x3C
};
var display = new oled(i2cBus, opts);
display.clearDisplay();
display.turnOnDisplay();
fs.createReadStream('./test.png')
.pipe(new PNG({ filterType: 4 }))
.on('parsed', function () {
setInterval(() => { drawImage(this) }, 1000);
});
function drawImage(image) {
let x = Math.floor(Math.random() * (display.WIDTH) - image.width / 2);
let y = Math.floor(Math.random() * (display.HEIGHT) - image.height / 2);
display.drawRGBAImage(image, x, y);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 648 B

View File

@ -1,108 +0,0 @@
{
"name": "oled-i2c-bus",
"version": "1.0.12",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "oled-i2c-bus",
"version": "1.0.12",
"dependencies": {
"rgpio": "file:local_modules/rgpio"
},
"devDependencies": {
"oled-font-5x7": "~1.0.0",
"png-to-lcd": "~1.0.2",
"pngjs": "^3.3.3",
"pngparse": "~2.0.1",
"temporal": "^0.3.8"
}
},
"local_modules/rgpio": {
"version": "0.0.1",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"bindings": "^1.5.0",
"node-addon-api": "^1.7.1"
}
},
"node_modules/bindings": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"dependencies": {
"file-uri-to-path": "1.0.0"
}
},
"node_modules/es6-shim": {
"version": "0.35.8",
"resolved": "https://registry.npmjs.org/es6-shim/-/es6-shim-0.35.8.tgz",
"integrity": "sha512-Twf7I2v4/1tLoIXMT8HlqaBSS5H2wQTs2wx3MNYCI8K1R1/clXyCazrcVCPm/FuO9cyV8+leEaZOWD5C253NDg==",
"dev": true
},
"node_modules/file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
},
"node_modules/floyd-steinberg": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/floyd-steinberg/-/floyd-steinberg-1.0.6.tgz",
"integrity": "sha512-gzlre+taSQzEY+nCusbHJFQ3zHXBkRAX4fe3szssPY/N/t1ClBX9hnHZM4o8ZvpdqLLUPEavuZ/Noj71ZaA8+A==",
"dev": true
},
"node_modules/node-addon-api": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz",
"integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg=="
},
"node_modules/oled-font-5x7": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/oled-font-5x7/-/oled-font-5x7-1.0.3.tgz",
"integrity": "sha512-l25WvKft8CgXYxtaqKdYrAS1P91rnUUUIiOXojAOvjNCsfFzIl1aEsE2JuaRgMh1Euo7slm5lX0w+1qNkL8PpQ==",
"dev": true
},
"node_modules/png-to-lcd": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/png-to-lcd/-/png-to-lcd-1.0.3.tgz",
"integrity": "sha512-y4X4mRvZUoMv1ruQimuXixC72HfPyPZHCxlSiQkwVjBAdYlQSnkp1N3EZkgVoS+CngJdTGGW9nMw9VBkfSH39Q==",
"dev": true,
"dependencies": {
"floyd-steinberg": "~1.0.4",
"pngparse": "~2.0.1"
}
},
"node_modules/pngjs": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz",
"integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==",
"dev": true,
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/pngparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/pngparse/-/pngparse-2.0.1.tgz",
"integrity": "sha512-RyB1P0BBwt3CNIZ5wT53lR1dT3CUtopnMOuP8xZdHjPhI/uXNNRnkx1yQb/3MMMyyMeo6p19fiIRHcLopWIkxA==",
"dev": true
},
"node_modules/rgpio": {
"resolved": "local_modules/rgpio",
"link": true
},
"node_modules/temporal": {
"version": "0.3.8",
"resolved": "https://registry.npmjs.org/temporal/-/temporal-0.3.8.tgz",
"integrity": "sha512-Oifg/Jy1FqoxgAHhfrwjnO9PKrqv9JYR/KgsmsMKjpPaYWdJmzWnCVhSFAxv7ygdYILj6Kd+v4YQtaxF0ZCjGA==",
"dev": true,
"dependencies": {
"es6-shim": "latest"
},
"engines": {
"node": ">=0.8.0"
}
}
}
}

View File

@ -1,19 +0,0 @@
{
"name": "oled-i2c-bus",
"version": "1.0.12",
"description": "NodeJS module for controlling oled devices on the Raspbery Pi (including the SSD1306 OLED screens)",
"main": "oled.js",
"devDependencies": {
"oled-font-5x7": "~1.0.0",
"png-to-lcd": "~1.0.2",
"pngjs": "^3.3.3",
"pngparse": "~2.0.1",
"temporal": "^0.3.8"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"rgpio": "file:local_modules/rgpio"
}
}

View File

@ -1,23 +0,0 @@
const main = async () => {
var oled;
const _rg = require('rgpio');
const _oled = require('/home/ichij/ocogeclub/ocoge/blocks/sensors/ssd1306/oled.js');
await _rg.rgpio_sbc();
var _opts = {
width: 128,
height: 64,
address: 0x3c,
bus: 5
};
oled = new _oled(_rg, _opts);
oled.clearDisplay();
oled.turnOnDisplay();
oled.drawCircle(63, 31, 8, 1)
}
main();