2022/01,江端さんの技術メモ

背景は、

階段の電気をつけっぱなしにすると、3分後にブザーが鳴るシステムを作ってみた

に記載した通りなのですが、家族から「警告音がうるさい!」と文句を言われて、システムを停止させております。

そこで、添付ファイルのようなものを実現したいと考えています。ただ、これを実現する回路図や、または、製品を見つけられずにおります。

ご知見のある方のアドバイスをお待ち申し上げております。


追記:読者の方から、「遅れ消灯スイッチ」
https://www2.panasonic.biz/ls/densetsu/haisen/switch_concent/cosmo_wide21/lineup/switch/delay/

を勧めて頂きました。しかし、私の環境では、階段に設置する3つのスイッチ(3路、4路スイッチ)を使うもの(私が、説明していませんでした)で、このデバイスは使えないと思います。


追記:さらに読者の方から「あけたらタイマ」の利用を教えて貰いました。
https://www2.panasonic.biz/ls/densetsu/haisen/switch_concent/cosmo_wide21/lineup/switch/timer/

『このスイッチ(親機、WTC5332W)はタイマー機能のほか、遅れ消灯機能もあります。これと、子機WT5652を3路の位置、Wt5654を4路の位置に使用すれば、いずれのスイッチからも遅れ消灯が可能かと思われます。』

仕様書を読んでみたら、ドンピシャと思われる記載がありました。

なるほど、これならできる(かもしれない)。

合計金額が、7900円 + 2600円 + 2900円 = 13000円 になりますね。

これでちゃんと動くのであれば、この出資には意味がありそうです。しかも、居留守対策もできそうです。

というか、この装置を買って、分解して、リバースエンジニアリングしてみてもいいな、と思っています。


ちなみに、居留守対策装置は、実家でも稼動中です。

実家の玄関のタイマーの設定

 

 

2022/01,江端さんの技術メモ

<論説の4要素>
(1)解説 (物事がどのようにして、なぜ起こるのかを説明する)→現在形
(2)叙述 (何が起ったのか述べる)→過去形
(3)描写 (図表によるイメージを与える)→現在形
(4)論拠 (理由を挙げることによって納得させる)→現在形

アブストラクト(要約)は通常現在形で書く→(1)解説
サマリー(概要)は通常過去形で書く→(2)叙述
■過去の研究(例えば参考文献にある)は通常過去形で書く→(2)叙述
恒久施設現在形で書く→(1)解説
特定の研究の為の実験手順および装置過去形で書く→(2)叙述
図表に示された結果現在形で書く→(3)描写
研究した試薬品、資料等の挙動過去形で書く→(2)叙述
結論部分では、結論そのものを除いては通常過去形で書く
導かれた結論(演繹)は、研究調査の条件に関係なく「一般真理」であるので、現在形で書く→(1)解説

仮定法は、書き手が「強い疑いを暗示したい場合」のみに使用する

(出典:NASAに学ぶ英語論文・レポートの書き方)

 

2022/01,江端さんの技術メモ

私が普段使っているDBは、PostgreSQLを使っているのですが、構築手順が面倒くさいし、なによりDBサーバ立てるのを省略したかったです。

ですので、SQLiteを使ってDB構築の手を抜くことにしました。

今日のところは、mattn/go-sqlite3 に _example/simple/simple.go というサンプルファイルがあったので、これを動くことを確認するところまでやりました。

/*
	C:\Users\ebata\kese\gonet-html\1-1
	go get github.com/mattn/go-sqlite3

	どういう訳か、VSCodeのデバッグでトレースができなかったので、fmt.Println("----->10") と入れて確認をしている。
	このプログラムは、

*/

package main

import (
	"database/sql"
	"fmt"
	"log"
	"os"

	_ "github.com/mattn/go-sqlite3"
)

func main() {
	os.Remove("./foo.db")

	fmt.Println("----->10")

	db, err := sql.Open("sqlite3", "./foo.db")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	sqlStmt := `
	create table foo (id integer not null primary key, name text);
	delete from foo;
	`
	_, err = db.Exec(sqlStmt)
	if err != nil {
		log.Printf("%q: %s\n", err, sqlStmt)
		return
	}

	fmt.Println("----->9")

	tx, err := db.Begin()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("----->8")

	stmt, err := tx.Prepare("insert into foo(id, name) values(?, ?)")
	if err != nil {
		log.Fatal(err)
	}
	defer stmt.Close()
	for i := 0; i < 100; i++ {
		_, err = stmt.Exec(i, fmt.Sprintf("こんにちわ世界%03d", i))
		if err != nil {
			log.Fatal(err)
		}
	}
	tx.Commit()

	fmt.Println("----->7")

	rows, err := db.Query("select id, name from foo")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()
	for rows.Next() {
		var id int
		var name string
		err = rows.Scan(&id, &name)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(id, name)
	}

	fmt.Println("----->6")

	err = rows.Err()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("----->5")

	stmt, err = db.Prepare("select name from foo where id = ?")
	if err != nil {
		log.Fatal(err)
	}
	defer stmt.Close()
	var name string
	err = stmt.QueryRow("3").Scan(&name)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(name)

	fmt.Println("----->4")

	_, err = db.Exec("delete from foo")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("----->3")

	_, err = db.Exec("insert into foo(id, name) values(1, 'foo'), (2, 'bar'), (3, 'baz')")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("----->2")

	rows, err = db.Query("select id, name from foo")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()
	for rows.Next() {
		var id int
		var name string
		err = rows.Scan(&id, &name)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(id, name)
	}

	fmt.Println("----->1")

	err = rows.Err()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("----->0")

}

もう一つのサンプルコード

https://qiita.com/geniusmaaakun/items/b3cb44de3b10a526be98 を参照させて頂き、微小修正

package main

/*
C:\Users\ebata\kese\gonet-html\1-1-1
sqliteをインストールする際の手順の確認

# ドライバのインストール
go get github.com/mattn/go-sqlite3

*/

import (
	"database/sql"
	"fmt"
	"log"
	"os"

	//インポート _にしないとコンパイルエラーになる。使用しない為
	_ "github.com/mattn/go-sqlite3"
)

var DbConnection *sql.DB

type Person struct {
	Name string
	Age  int
}

func main() {

	os.Remove("./example.sql") // これを入れないと、DBが太り続ける

	//1
	//DBを開く  なければ作成される
	DbConnection, _ := sql.Open("sqlite3", "./example.sql")
	//終わったら閉じる
	defer DbConnection.Close()
	//DB作成 SQLコマンド
	cmd := `CREATE TABLE IF NOT EXISTS person(
        name STRING,
        age  INT)`

	//実行 結果は返ってこない為、_にする
	_, err := DbConnection.Exec(cmd)

	//エラーハンドリング
	if err != nil {
		fmt.Println("エラー")
		log.Fatalln(err)
	}

	//ターミナル
	//sqlite3
	//.table
	//SELECT * FROM tablename;
	//で確認

	//2 CRUD処理
	//Create
	//データを追加
	//VALUES (?, ?)  値は後で渡す。セキュリテイの関係でこのようにする方がいい
	//SQLインジェクション 悪意あるコマンドでDBが操作されてしまうのを防ぐ ?でエスケープしてくれる
	cmd = "INSERT INTO person (name, age) VALUES (?, ?)"
	//実行
	//レコードを取得する必要のない、クエリはExecメソッドを使う
	//第二引数からは、コマンド?部の値
	_, err = DbConnection.Exec(cmd, "Nancy", 20)
	if err != nil {
		log.Fatalln(err)
	}

	_, err = DbConnection.Exec(cmd, "Mike", 20)
	if err != nil {
		log.Fatalln(err)
	}

	_, err = DbConnection.Exec(cmd, "Tom", 55)
	if err != nil {
		log.Fatalln(err)
	}

	//Update
	//データの更新 Mike が存在する場合
	cmd = "UPDATE person SET age = ? WHERE name = ?"
	_, err = DbConnection.Exec(cmd, 25, "Mike")
	if err != nil {
		log.Fatalln(err)
	}

	//Read
	//Get  All
	//マルチセレクト
	//データ全てをループで表示
	//Queryは全て取得する
	cmd = "SELECT * FROM person"
	rows, _ := DbConnection.Query(cmd)
	defer rows.Close()
	//structを作成
	var pp []Person

	//取得したデータをループでスライスに追加 for rows.Next()
	for rows.Next() {
		var p Person
		//scan データ追加
		err := rows.Scan(&p.Name, &p.Age)
		if err != nil {
			log.Println(err)
		}
		pp = append(pp, p)
	}
	err = rows.Err()
	if err != nil {
		log.Fatalln(err)
	}
	//表示
	for _, p := range pp {
		fmt.Println(p.Name, p.Age)
	}

	//特定のデータを取得
	cmd = "SELECT * FROM person where age = ?"
	//age = 20にして実行
	//QueryRowは最初の一件だけ取得する。

	//row := DbConnection.QueryRow(cmd, 20)
	//row := DbConnection.QueryRow(cmd, 25)
	row := DbConnection.QueryRow(cmd, 55)

	var p Person
	err = row.Scan(&p.Name, &p.Age)
	if err != nil {
		//データがなかったら
		if err == sql.ErrNoRows {
			log.Println("No row")
			//それ以外のエラー
		} else {
			log.Println(err)
		}
	}
	fmt.Println(p.Name, p.Age)

	//Delete
	//データの削除  全て
	cmd = "DELETE FROM person WHERE name = ?"
	_, err = DbConnection.Exec(cmd, "Nancy")
	if err != nil {
		log.Fatalln(err)
	}

	//マルチセレクト  テーブルもSQLインジェクション対策
	//こちらを推奨
	//データを構造体に入れて表示
	//テーブルはSQLインジェクション対策が使えない
	tableName := "person"
	//テーブル名指定は?が使えない為、%sを使う。
	//後に対応されるかも?
	cmd = fmt.Sprintf("SELECT * FROM %s", tableName)
	rows1, _ := DbConnection.Query(cmd)
	defer rows1.Close()
	var pp1 []Person
	//パターンとして覚える
	for rows1.Next() {
		var p Person
		//データを構造体に追加
		err := rows1.Scan(&p.Name, &p.Age)
		if err != nil {
			log.Println(err)
		}
		//ppに追加
		pp1 = append(pp1, p)
	}
	//まとめてエラーチェック
	err = rows1.Err()
	if err != nil {
		//エラーなら終了
		log.Fatalln(err)
	}
	for _, p := range pp1 {
		fmt.Println(p.Name, p.Age)
	}
}

 

2022/01,江端さんの技術メモ

Pythonのスクレイピングを、Golangで記述してみる。

まずpythonの記述です。

# -*- coding: utf-8 -*-
from pyquery import PyQuery

q = PyQuery('https://kabutan.jp/stock/?code=7203')
sector = q.find('#stockinfo_i2 > div > a')[0].text
print(sector)

これでターゲットとなるhtml部分は、多分ここ

<div id="stockinfo_i2">
<dl>
<dt>業績</dt>
<dd><img src="/images/cmn/gyouseki_2.gif" title="今期予想" /></dd>
</dl>

<div>
<a href="/themes/?industry=17&market=1">輸送用機器</a>
</div>

これをgolangで実現するには、このようにコーディングするようです。

package main

import (
	"fmt"

	"github.com/PuerkitoBio/goquery"
)

func main() {
	//get_url_info, err := goquery.NewDocument("https://profile.yahoo.co.jp/search/?w=トヨタ自動車")
	get_url_info, err := goquery.NewDocument("https://kabutan.jp/stock/?code=7203")
	if err != nil {
		fmt.Println("get html NG")
	}

	//result := get_url_info.Find("div > div > table > tbody > tr > td")
	//result := get_url_info.Find("div > div > a")
	result := get_url_info.Find("#stockinfo_i2 > div > a")
	result.Each(func(index int, s *goquery.Selection) {
		fmt.Println(s.Text())
	})
}

出力結果は以下の通りです。

ebata@DESKTOP-P6KREM0 MINGW64 ~/kese/gonet-html
$ go run main3.go
輸送用機器

こうやると、もっと簡単にできそう。

package main

import (
	"fmt"

	"github.com/PuerkitoBio/goquery"
)

func main() {

	q, err := goquery.NewDocument("https://kabutan.jp/stock/?code=7203")
	if err != nil {
		fmt.Println("get html NG")
	}

	name := q.Find("div.company_block > h3").Text()
	fmt.Println(name)

	code_short_name := q.Find("#stockinfo_i1 > div.si_i1_1 > h2").Text()
	fmt.Println(code_short_name)

	market := q.Find("span.market").Text()
	fmt.Println(market)

	unit_str := q.Find("#kobetsu_left > table:nth-child(4) > tbody > tr:nth-child(6) > td").Text()
	fmt.Println(unit_str)

	sector := q.Find("#stockinfo_i2 > div > a").Text()
	fmt.Println(sector)

}

 

 

2022/01,江端さんの技術メモ

参照 : https://github.com/PuerkitoBio/goquery

goqueryは、jQueryに似た構文と機能群をGo言語に提供するものです。

$ go get github.com/PuerkitoBio/goquery

で使うことができるようになります。

サンプルプログラムで、この内容の解説を試みます。

package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/PuerkitoBio/goquery"
)

func ExampleScrape() {
	// Request the HTML page.

	res, err := http.Get("http://kobore.net")

	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
		log.Fatalf("status code error: %d %s", res.StatusCode, res.Status)
	}

	// Load the HTML document
	doc, err := goquery.NewDocumentFromReader(res.Body)
	if err != nil {
		log.Fatal(err)
	}

	doc.Find("input").Each(func(i int, s *goquery.Selection) {
		// For each item found, get the title
		title, _ := s.Attr("type")
		fmt.Printf("Review %d: %s\n", i, title)
	})

	/*
		上記によって以下の4行がピックアップされる。

		<input type="hidden" name="cx" value="010448971387544815344:gehqdwxqnlo" />
		<input type="hidden" name="ie" value="Shift_JIS" />
		<input type="text" name="q" size="10" />
		<input type="submit" name="sa" value="Search" />
	*/

}

func main() {
	ExampleScrape()
}

対象となる、Webのhtmlは以下の通り

(前略)

<TITLE>kobore.net</TITLE>
</head>

<TD ALIGN="right">
<A HREF="./index-en.shtml">English</A> /
Japanese
</TD>

<div align="RIGHT">
<img src="https://www.kobore.net/KOBORE-small.jpg">
<form id="cse-search-box" action="https://google.com/cse" target="_blank">
<input type="hidden" name="cx" value="010448971387544815344:gehqdwxqnlo" />
<input type="hidden" name="ie" value="Shift_JIS" />
<input type="text" name="q" size="10" />
<input type="submit" name="sa" value="Search" />
</form>
</div>

<body BGCOLOR="#F0FFA0">

<H1 ALIGN="center">こぼれネット</H1>
<H2 ALIGN="center">
www.kobore.net
</H2> 

(後略)

出力結果は、以下の通り。

C:\Users\ebata\kese\gonet-html>go run main.go
Review 0: hidden
Review 1: hidden
Review 2: text
Review 3: submit

2021/12,江端さんの技術メモ

githubの中のファイルを直接編集したいだけなのに、色々調べたけど、余計な説明が多すぎて困っています。

上記の2つ(GitHub Repositories, GitHub Pull Request and Issues)がインストールされていることが前提です。

以下の操作をやるとできるようになるようです。

ブラウザに次の画面が次の画面が立ち上がってきます。

VSCodeの方に以下のメッセージが出てくるので「許可」を押下して下さい。

VSCodeにリポジトリの内容が表示されます。

編集するファイルを選んで、変更します。"test5"と記載して、ファイルをセーブして、以下の手続を行います。

コミットのメッセージを記載する。

以下のボタンを押して下さい。

Webで、反映されているのが確認できます。

本来は、ブランチとかマージとか、いろいろできるのでしょうが、とりあえず、iPad用の編集用に使えれば足りるので、これでいいのです。

https://vscode.dev で、編集もできそうだ、ということも確認しました。

ーーーー

コミットができなかったりするので、できたケースをもう一つ

変更してセーブすると「M」が表示されるので、以下の手順でコミットを進める。

の手順でコミットができるようです。

反映されています。

2021/12,江端さんの技術メモ

何だか分からんけど、動いたのでメモっておきます。

/C/Users/ebata/kese/VSC_C++_test

というディレクトリに、main.cpp とsub.cppを置く。

#include <stdio.h>

int sub(int, int);

int main() {
    int a = sub(2, 3);
    printf("%d\n", a);

    return 0;
}
#include <stdio.h>

int sub(int a, int b) {
    int c;
    c = a + b;

    return c;
}
  • 「Ctrl+Shift+P」 で、コマンドパレットを開く
  • 「C/C++: Edit configurations...」 を選択
  • 「.vscode」 フォルダの中に 「c_cpp_properties.json」 ファイルが作成される

c_cpp_properties.jsonは、以下のようになっている。

{
    "configurations": [
        {
            "name": "Win32",
            "includePath": [
                "${workspaceFolder}/**"
            ],
            "defines": [
                "_DEBUG",
                "UNICODE",
                "_UNICODE"
            ],
            "compilerPath": "C:\\msys64\\mingw64\\bin\\gcc.exe",
            "cStandard": "gnu17",
            "cppStandard": "gnu++14",
            "intelliSenseMode": "windows-gcc-x64"
        }
    ],
    "version": 4
}
  • 「Ctrl+Shift+P」 で、コマンドパレットを開く
  • 「Tasks: Configure Task」 を選択する
  • 「テンプレートから tasks.json を生成」 をクリック
  • 「Others 任意の外部コマンドを実行する例」 をクリック
  • 「.vscode」 フォルの中に 「tasks.json」 ファイルが作成される
  • 「tasks.json」 を下記のように変更する
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "sample",
            "type": "shell",
            "command": "g++",
            "args": [
                "-g",
                "main.cpp"
            ],
            "group": "build"
        },
        {
            "type": "cppbuild",
            "label": "C/C++: g++.exe アクティブなファイルのビルド",
            "command": "C:\\msys64\\mingw64\\bin\\g++.exe",
            "args": [
                "-fdiagnostics-color=always",
                "-g",
                "${file}",
                "sub.cpp" // ←ここがポイント
                "-o",
                "${fileDirname}\\${fileBasenameNoExtension}.exe"
            ],
            "options": {
                "cwd": "${fileDirname}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "detail": "デバッガーによって生成されたタスク。"
        }
    ]
}
  • 「Ctrl+Shift+D」 でデバッグを実行する
  • 環境の選択のドロップダウンで、「C++ (GDB/LLDB)」を選択
  • 「.vscode」 フォルの中に 「launch.json」 ファイルが作成される
{
    // IntelliSense を使用して利用可能な属性を学べます。
    // 既存の属性の説明をホバーして表示します。
    // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "g++.exe - アクティブ ファイルのビルドとデバッグ",
            "type": "cppdbg",
            "request": "launch",
            "program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${fileDirname}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "miDebuggerPath": "C:\\msys64\\mingw64\\bin\\gdb.exe",
            "setupCommands": [
                {
                    "description": "gdb の再フォーマットを有効にする",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                },
                {
                    "description": "逆アセンブリ フレーバーを Intel に設定",
                    "text": "-gdb-set disassembly-flavor intel",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "C/C++: g++.exe アクティブなファイルのビルド"
        }
    ]
}

こんな感じで出てくる。

現時点では動いたり動かなかったりと、安定していません。

2021/12,江端さんの技術メモ

「ファイル」 → 「フォルダを開く」でフォルダを選択すれば、settings.jsonが出てこなくなる

フォルダの中に、".vscode"のディレクトリがって、その中には、以下のファイルが入っていることも必要(多分)

Visual Studio Code C/C++ 検討中

 

2021/12,2021/12,江端さんの忘備録,江端さんの技術メモ

Open Street Map(以下OSMといいます)とは、「自由に利用でき、なおかつ編集機能のある世界地図を作る共同作業プロジェクト」のことです。

Open Street Map (OSM) is a collaborative project to create a freely available, yet editable, map of the world.

一般的には、"xxxxx.osm"ファイルという名前の地図情報ファイルの意味で使われることが多いです。

In general, it is often used to mean a map information file named "xxxxxx.osm" file.

このようなomsファイルは、地図を使った交通シミュレーションを行う研究員にとっては、大変助かります。

These oms files are very helpful for researchers who are working on map-based traffic simulations.

しかし、OSMの地図は、世界中の人達の協力によって作られているものですし、そもそも、地図は常に拡張や変更を続けるものです。

However, OSM's maps are made with the cooperation of people from all over the world, and in the first place, maps are always expanding and changing.

「完璧な地図」などはありません。

There is no such thing as a "perfect map.

特に、自分の研究でomsファイルを使う場合、必要に応じて地図情報を正しく修正したいことがあります。

Especially when using oms files in my own research, I may want to modify the map information correctly if necessary.

-----

そんな訳で、今朝から、OSMの地図の編集を試みています。

That's why I've been trying to edit the OSM map since this morning.

以下は、横浜国立大学の敷地内の地図ですが、この中に、「自動車が入れる道」が記載されていなかったので、先程追記してみました。

The following is a map of the grounds of Yokohama National University, which I have just added to the map because it did not include a "car road".

なぜ、私が大学キャンパスの道を知っているのか ―― そりゃもう、このキャンパスの中を、何百回、自動車と足で走り回り、GPSロガーでデータを取りまくったことか、分かりません ―― 仕事(屋外実証実験)で。

How do I know my way around a university campus? Well, I can't tell you how many times I've driven around this campus by car and foot, taking data with my GPS logger for my work (field demonstration).

-----

ところで、今朝の私のこの修正が、ボタン一つでOSM地図情報に登録されてしまって、唖然としています。

By the way, I was stunned to see that this correction of mine this morning was registered in the OSM Map Information with the click of a button.

修正後は、私の記載した地図が、世界中で反映されてしまうことになります。

After the revision, the map I described will be reflected all over the world.

―― 私の過失、または、悪意で、地図を改竄(かいざん)してしてしまったらどうするんだ?

"What if the map is tampered with due to my negligence or malicious intent?"

と、かなり不安な気持ちになってきました。

I came to feel quite uneasy.

なにしろ、今回の修正は、私の初めてのトライアルですので。

After all, this is my first trial with this modification.

そのような場合でも、多分、『だれかが私の改竄を修正する』、そして、『私が間違いを続ければ、私をOSMメンバから除名する』と期待しているのですが ――

Even in that case, I'm hoping that maybe "someone will correct my falsification" and "if I continue to be wrong, they will expel me from OSM membership" -- but I'm not sure.

それにしても、「自由に利用でき、なおかつ編集機能のある世界地図を作る共同作業プロジェクト」って凄いなぁ、と実感しています。

Anyway, I really feel that "a collaborative project to create a freely available, yet editable world map" is a great idea.

=====

実行手順

Step.1 https://www.openstreetmap.org/ から、「ユーザ登録」

Step.2 ユーザ登録します。

私の場合、サードパーティ認証にGoogleのログインを使うことにしました。

その後は、ガイダンス画面に入るので、そこで一通り勉強してから、編集作業をします(今日は割愛します)。

以上