For Chromecast - 1st Generation

当年曾入手Chrome第一代,折腾过后,还是放弃了。原因有两个:一要联网才能用,二要能访问Google。相关的资料整理如下:

刷机

刷机,为了获取root权限,也为了获取更多的可能性(最后的结论是,然并卵…)。相关的教程都在:

记得当时还入手了Arduino Nano(好像吧),用于破解。

开发

只是好奇查了相关的开发资料,但一直没深入。

然后,就酱……

Git Server over SSH

搞了几天,终于弄懂了自建Git服务。正如绝大多数的教程所说,基于ssh来部署git服务,是最简单的。

1)服务器和客户端都安装Git。

sudo apt-get update
sudo apt-get install git

2)服务器上建立Git仓库。我比较懒,就用现有的用户,比如用户名为:user。用user登录后,执行命令。git init --bare是用于建立裸仓。执行成功后,会建立project.git文件夹,确保user对该文件夹有读写权限。

mkdir /path/git
cd /path/git
git init --bare project.git

3)客户端clone项目。ssh://是指,基于ssh的git服务。user就是用户名。server_ip就是服务器ip,也可以是域名。22是ssh服务的端口,根据部署的ssh服务而定。/path/git/project.git就是前面建立的项目路径。

git clone ssh://user@server_ip:22/path/git/project.git

然后就可以愉快地各种Git操作了。

至于后面增加安全性,可以新增一个git用户,设置其不能登录shell,并采用证书登录等等,可以参考网上的教程。例如: 廖雪峰的官方网站:搭建Git服务器

Make Shell Support Chinese

手上有个远古时代的上网本,华硕(ASUS) EeePC 900。删掉原来的Windows XP,装上Lubuntu 16.10。原电池废了,淘宝换了个新的,续航能达到5小时(大概吧)。但是一般用来远程ssh到raspberry pi,没必要开启图形界面(特别是发现用screen可以同一界面打开多个shell)。需要解决的问题是中文的显示和输入。Google过后,最终的解决方案是fbterm(完美显示中文) + fcitx-fbterm(实现中文输入)。

fbterm的安装参考这个(英文):https://fcitx-im.org/wiki/Fbterm

中文版本的完整安装教程,参考这个:http://ikuduku.com/blog/fbterm-display-and-input-Chinese-in-tty

关于中文输入法,我选择google拼音(fcitx-googlepinyin)。记录一下相关操作:

1)安装

#安装相关软件
sudo apt-get install fbterm fcitx fcitx-fbterm fcitx-googlepinyin fcitx-configtool
#让fbterm可以设置快捷键,主要是切换输入法
sudo setcap 'cap_sys_tty_config+ep' /usr/bin/fbterm
#把当前用户加入到video组
sudo gpasswd -a <your username> video

2)编辑当前用户的配置

vi ~/.fbtermrc

修改如下:

#设置字体
font-name=Mono
#设置字体大小
font-size=14
#设置输入法
input-method=fcitx-fbterm

3)设置开机启动

#设置开机进入shell界面,这是Ubuntu 16.04及以后版本的设置方法
sudo systemctl set-default multi-user.target
#设置进入图形界面的命令,然后用`sudo startx`命令即可进入图形界面
sudo sh -c "echo \#\!/bin/sh > /usr/local/bin/startx"
sudo sh -c "echo systemctl start lightdm >> /usr/local/bin/startx"
sudo chmod +x /usr/local/bin/startx
#设置进入shell后自动启动fbterm,而图形界面的shell则不会启动fbterm
printf '\nif [ $TERM = 'linux' ]; then\n  fcitx-fbterm-helper -l\nfi' >> ~/.bashrc

大概就这样了。使用过程中,还是有一点不习惯。例如快捷键的变换,Ctrl + Alt + F1 ~ F6 不能切换tty,而是切换字符编码,使用 Ctrl + Alt + 1 ~ 0 可以切换10个窗口。

Batch Rename Using Shell Script

一般一个月一次整理孩子的照片。但是老婆的手机和单反拍出来的照片,文件名都不统一。要统一采用拍照时间做为文件名的话,比较麻烦。本来想用Python3写个脚本处理的,但是官方没有提供获取EXIF信息的方法。找打其它包,也不怎么好用。但是今晚发现原来有个shell命令挺好用的,就是EXIF。

于是就写了个shell脚本,如下:

#!/bin/bash

path=/home/fox/pics

i=$(ls $path/*.JPG)

for j in $i
do
    d=$(exif -t "DateTime" $j | grep Value)
    d=${d/  Value: /IMG_}
    d=${d//:/}
    d=${d// /_}
    $(mv $j ${d}.jpg)
done

这里采用的统一文件名格式是IMG_yyyyMMdd_HHmmss.jpg。由于采用字符串替换的语法,所以只能用bash运行。

SSL for Free

某日发现了提供免费SSL证书的网站——www.sslforfree.com,立马手动申请了个证书来玩。部署以后,非常感动,重点是Chrome和FireFox都支持!曾在某知名网站申请过免费证书,总是申请失败。心灰意冷,本来准备买个廉价的付费版,幸好发现这网站!

免费虽好,但有效期只有3个月,而且到期后只能手动更新证书。不过找到提供该免费证书的网站——Let’s Encrypt(https://letsencrypt.org),以及该网站提供的自动更新证书的开源软件certbot(https://certbot.eff.org)。certbot首页就有安装教程,对应不同HTTP服务和操作系统。安装完毕后,执行以下命令,就可以获取证书了

#验证域名并获取SSL证书
sudo certbot certonly --webroot -w /var/www/example -d example.com -d www.example.com

最后,设置个自动更新,就安枕无忧了。

PS.既然有了免费的证书,何不部署个HTTP 2.0?

Getting Start with ESP8266

简单玩过NodeMCU之后,想获取更多的数据,就是多加几个传感器。但是NodeMCU只有一个ADC接口,于是找到利用Arduino与ESP8266结合的解决方案。Arduino的不同版本的接口数量不同,而手头上的Pro Micro就有4个ADC了,勉强够用。ESP8266就是NodeMCU的核心,相比NodeMCU更少接口,但体积更小,价格更低。于是入手了两个ESP8266来折腾。

First of All,刷固件。

刷固件的官方教程

最新的固件下载

官方入门教程

大概就这些了。话说,计划中的植物环境数据收集平台升级版,都拖好久了……

First NodeMCU Project

说起物联网,最早接触的是Arduino。可是入手Arduino Mega后,一直没做出什么好玩的东西,以致Mega丢在角落里好几年。近来在部门经理的怂恿下,入手了NodeMCU,做了个检测盆栽的土壤湿度。本来想在Github开个项目,但是这第一版太简单了,就随便记录一下。

NodeMCU的特点,在于自带WiFi(还可以使用AP模式),而且价格便宜。当然,缺点也在WiFi,比较耗电。为了省电,可以设置网卡的硬件参数(wifi.setphymode()),关闭WiFi(wifi.sleeptype()),甚至是整块板进入深度睡眠模式(node.dsleep(), rtctime.dsleep())。其开源、基于Lua的开发简单、尺寸迷你等优点,也是其好玩之处。

这个项目很简单,就是NodeMCU连个土壤湿度检测模块,定时(10分钟)获取一次数据,并上传到服务器。服务器是采用树梅派,用Python3,利用Flask框架,写了个HTTP服务,用于保存提交的数据,并做数据展示。数据都保存在MySQL数据库。

NodeMCU上的init.lua

print("\n")
print("ESP8266 Started")

dsleepTime = 630000000
ssid = "my-wifi"
password = "123456"
serverIp = "192.168.1.1"
serverPort = 8080

wifi.setphymode(wifi.PHYMODE_N)
wifi.setmode(wifi.STATION)
wifi.sta.config(ssid, password)
tmr.alarm(0,1000,1,function() 
    curIp = wifi.sta.getip()
    if curIp ~= nil then
        print("Current IP:"..curIp)
        tmr.stop(0)
        sendData(readValue(0, 5))
    end
end)

--发送数据到服务器    
function sendData(value)
    print("sendData start")
    conn = net.createConnection(net.TCP, false)
    conn:on("receive", function(conn, pl)
        print("Send data with value: "..value)
        print("Result:\n"..pl)
        conn:close()
        conn = nil
        wifi.sta.disconnect()
        
        node.dsleep(dsleepTime)
    end)
    conn:connect(serverPort, serverIp)
    conn:send("GET /gather/?key=123456&value="..value
        .." HTTP/1.1\r\nHost: " + serverIp + "\r\n"
        .."Connection: keep-alive\r\nAccept: */*\r\n\r\n")

    --connect time out
    tmr.alarm(1,5000,1,function()
        print("[error]connet to server time out")
        --conn:close()
        --conn = nil
        --wifi.sta.disconnect()
        tmr.stop(1)
        
        node.dsleep(dsleepTime)
    end)
end

--读取土壤湿度数据
--一次有效的采样,最少取3次数据,去掉最大值和最小值,再计算平均值
function readValue(adcPin, readTimes)
    if readTimes <= 2 then
        readTimes = 3
    end
    
    local curValue = 0
    local maxValue = 0
    local minValue = 0
    local sumValue = 0
    
    for i = 0, readTimes - 1 do
        curValue = adc.read(adcPin)
        sumValue = sumValue + curValue
        if maxValue < curValue then
            maxValue = curValue
        end
        if (minValue == 0) or (minValue > curValue) then
            minValue = curValue
        end
    end
    sumValue = sumValue - maxValue - minValue
    curValue = math.floor(sumValue / (readTimes - 2))

    return curValue
end

服务器上的HTTP服务,文件site.ini

[uwsgi]
socket = 127.0.0.1:8080
processes = 2
threads = 1
plugins = python3
master = true
pythonpath = /opt/work/web_gather
chdir = /opt/work/web_gather
module = site
callable = app
chmod-socket = 777
memory-report = true

服务器上的HTTP服务,文件site.py

#!/bin/python3

from datetime import datetime
from flask import Flask, request, abort, render_template
from flask.ext.sqlalchemy import SQLAlchemy
from sqlalchemy import desc

app = Flask(__name__)
app.config['SECRET_KEY'] = '123456'

app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:123456@127.0.0.1/web_gather'
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True

app.config['HUMIDITY_MIN'] = 740

db = SQLAlchemy(app)

class Humidity(db.Model):
    __tablename__ = 'humidity'
    id = db.Column('id', db.Integer, primary_key=True)
    createDate = db.Column('create_date', db.DateTime)
    sourceValue = db.Column('source_value', db.Integer)
    value = db.Column('value', db.Integer)

    def __repr__(self):
        return '<Humidity % r>' % self.id

@app.route('/', methods=['GET', 'POST'])
def index():
    key = request.args.get('key', '')
    
    if key == app.config['SECRET_KEY']:
        sourceValue = request.args.get('value', '0')
        value = (1024 - int(sourceValue)) / 1024 * 100
        curTime = datetime.today()
        humidity = Humidity(createDate=curTime, sourceValue=sourceValue, value=value)
        db.session.add(humidity)
        db.session.commit()
        return 'true'
    
    humidities = Humidity.query.order_by(desc(Humidity.createDate)).limit(500)
    return render_template('humidity.html', humidities=humidities)

if __name__ == '__main__':
    app.run(debug=False, host='127.0.0.1', port=8080)
    #app.debug = False
    #app.run()

MySQL的表定义

CREATE TABLE `humidity` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `create_date` datetime DEFAULT NULL,
    `source_value` int(11) DEFAULT NULL,
    `value` int(11) DEFAULT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2554 DEFAULT CHARSET=utf8

Backup the Hard Disk of CentOS

上星期终于搞掂了办公室的CentOS备份。一开始,我们把硬盘A完全复制到硬盘B(用dd命令拷贝整个硬盘),产生了很多误会,也搞出不少问题,差点以为把硬盘A的数据搞丢了。

后来才发现,CentOS挂载硬盘分区时,根据分区的UUID来挂载的。由于两个硬盘的数据完全一致(包括各分区的UUID也一致),所以即使以硬盘A启动电脑,也可能挂载了硬盘B的分区。最后将错就错,按如下步骤解决问题:

1)修改硬盘B中所有分区的UUID

参考文章:linux下硬盘uuid查看及修改设置

Ext4的分区可以按照该文章,修改分区UUID:

uuidgen | xargs tune2fs /dev/sdb1 -U

但是swap分区不行,只能格式化一下,让其重新生成UUID:

#操作之前,先取消挂载
swapoff /dev/sdb2
#格式化swap分区
mkswap /dev/sdb2

修改后,可以下命令查看各分区的UUID:

blkid /dev/sdb1

2)修改硬盘B上的相关配置文件

此步骤是为了让硬盘B也能直接启动。就是说硬盘A出了什么故障,直接用硬盘B就可以启动服务器了。

a)修改分区挂载文件/etc/fstab,把对应分区的UUID改为新的。 b)修改grub配置文件/boot/grub/grub.conf,把根目录的分区UUID改为最新的。

3)同步两个硬盘的文件

这里采用rsync命令,把硬盘A的数据自动同步到硬盘B上。

a)把硬盘B的根目录挂载到/media/sdb3 b)创建文件/media/rsync_exclude文件,把要排除的文件夹或文件录进去,一行一个,参考内容如下:

/boot/*
/dev/*
/media/*
/lost+found
/proc/*
/sys/*
/tmp/*
/etc/fstab

c)执行以下命令,立即同步文件(以root用户执行):

rsync -avzP --delete --exclude-form=/media/rsync_exclude / /media/sdb3 >> /media/rsync.log

参考:

4)优化

后面考虑把硬盘B做成USB移动硬盘,这样可以在需要时才接上电源。再考虑接上硬盘B后自动执行同步命令。

Got Kindle3

终于还是入手了Kindle3,200RMB的二手货,成色很新。由于带键盘,也有比较成熟的软件,所以非常喜欢。记录一下入手后的折腾经历吧。

1)升级最新固件(fireware)

从官网下载最新固件(目前最新是3.4.2):

升级固件时,按照所需版本,一个一个地升。升级到最新版,最大的作用是可以注册美国亚马逊账号。其它的功能,包括阅读PDF(自动切除白边)、漫画等,都很方便。

2)越狱(Jailbreak)

详细操作,上面会详细记录。简单来说,就是下载对应的版本,然后刷进系统。本链接还包括修改默认屏保(ScreenSavers)、修改字体(Fronts)、USB有线网(USBNetwork)、Python等等。

3)快捷键(launchpad)

一个热键管理程序,可以把shell脚本,包括启动程序的脚本,做成热键,非常好用!

4)命令窗口(Terminal)

用launchpad启动,即可进入shell终端,然后就可用编写shell脚本、修改系统文件、ssh远程到其它机器等等。总之就是非常强大。

5)音乐播放器(MPlayer)

一边播放音乐,一边看书,也是不错的。特别要说的是,Kindle3自带的喇叭,音质比预想的好很多。

6)字典(Dictionary)

下载其它字典,并且可以替换系统默认的字典。

7)中文输入法

8)其它

这里都有汇总了几乎所有的软件,包括上面提到的。

Getting Start with NodeMCU

曾经在“闲鱼”(淘宝二手)上看到有人卖NodeMCU的开发板,查了发现这东西很便宜(30RMB以下可以买到),而且自带WiFi,非常适合打开“物联网”的大门。直到前几天,跟经理说起关于怎样控制窗户的开关,才又提起这个,并买了个来玩。

详细介绍

针脚定义

NodeMCU Pin Map

官方文档

入门教程

官方网站(http://www.nodemcu.com/)上没有找到官方的入门教程,但是找这一些比较好的:

1)一个比较全面的教程(针对Windows) http://nodemcu-dev.doit.am/ 2)NodeMCU 物联网开发快速上手(适合Linux用户) http://tinylab.org/nodemcu-kickstart/

官方论坛([http://bbs.nodemcu.com/][8])上也有一个系列的入门教程:

Lua语言介绍

关于NodeMCU上使用的Lua,这里有个不错的教程 https://moonbingbing.gitbooks.io/openresty-best-practices/content/lua/main.html