My Translator In ArchLinux(3)

Using redis for cache the dictionary.

    # In C, it's simple to use do...while(), but in python, we need to judge the input, 
    # Fortunately, the input is very simple, because get infos from RedisQue is blocking.
    # Forever Listening...
    while True:
        # Key in RedisQueue is 'dic', and we simply get its content:
        q = RedisQueue('dic')
        # cmdargs = q.get()
        # cmdargs = str(sys.argv) ## args
        to_be_refer_word = q.get()
        try:
            result = my_dict_reader.get_dict_by_word(str(to_be_refer_word))  ## Using args[1] for querying
            print result[0].values()[0]		## output result in terminal
            result_str = "\'<span color=\"green\" size=\"14000\">"+result[0].values()[0]+"</span>\'"	## Build the command line for notify-send
            call(["notify-send", to_be_refer_word, result_str])		## Call notify-send to print on screen, last for 5 seconds
        except Exception, e:
            print "Not Find!"

Then we write the query file named refer.py:

#!/usr/bin/python2
# -*- coding: utf-8 -*-
# For using RedisQueue to fetch the refer words 
import sys
from RedisQueue import RedisQueue

q = RedisQueue('dic')
q.put(str(sys.argv[1]))


Add the following lines as /usr/bin/mydic:

# Using redis
python2 /home/Trusty/code/python/mypython/stardict/refer.py $@


This will greatly improve the refer time, you could get the real-time result via mydic New_Words

Porting Weather APP Into Node.js

Website Design

Use express for generating the whole website.

$ pwd 
/home/Trusty/code/nodejs/weather
[Trusty@~/code/nodejs/weather]$ express weather

The express framework will be generated.

Add following dependencies into the weather/package.json:

    "jade": "~1.3.0", 
    "mongodb": "*",
    "monk": "*"

Install packages:

$ cd weather
$ npm install

mkdir data, this command will create a directory named data which is used for holding our mongodb.
Now visit http://localhost:3000/ you will see the demo html website.

This website should have the inteface for operating the database(MongoDB), so I will add some sub-pages for handling the request for insert and query the database.

Insert Records Into MongoDB

Design database in MongoDB:

$ mongo
$ show dbs
admin       (empty)
local       0.078GB
my-website  0.078GB
mydb        0.078GB
nodetest1   0.078GB
test        (empty)
$ use weathertest

The DataSet should be designed as following:

{
    "_id" : 1234,
    "AQI" : "70",
    "Level" : "良", 
    "FirstPollution" : "臭氧1小时", 
    "PM2_5" : "51", 
    "PM10" : "70", 
    "CO" : "0.148", 
    "NO2" : "31", 
    "O3_1hour" : "168", 
    "O3_8hour" : "68", 
    "S02" : "13" 
}

So the insert sentense should be like following:

db.usercollection.insert({ "AQI" : "70", "Level" : "良", "FirstPollution" : "臭氧1小时", "PM2_5" : "51", "PM10" : "70", "CO" : "0.148", "NO2" : "31", "O3_1hour" : "168", "O3_8hour" : "68", "SO2" :"13"})

Verify the insert result via:

> db.usercollection.find().pretty()
{
	"_id" : ObjectId("53ba7e137346b7523d951084"),
	"AQI" : "70",
	"Level" : "良",
	"FirstPollution" : "臭氧1小时",
	"PM2_5" : "51",
	"PM10" : "70",
	"CO" : "0.148",
	"NO2" : "31",
	"O3_1hour" : "168",
	"O3_8hour" : "68",
	"SO2" : "13"
}

Should add more informations into the database, for example the temperature/humidity, which could also be fetched via npm package.
First delete the inserted item via following command:

> db.usercollection.remove({"_id" : ObjectId("53ba7e137346b7523d951084")});
WriteResult({ "nRemoved" : 1 })
> db.usercollection.find().pretty()

Then insert a new organized records and verify the insertion :

db.usercollection.insert({ "Temperature" : "21.9", "DewPoint" : "19.93", "Humidity" : "0.89", "Pressure" : "1004.85", "Ozeone" : "289.03",  "AQI" : "70", "Level" : "良", "FirstPollution" : "臭氧1小时", "PM2_5" : "51", "PM10" : "70", "CO" : "0.148", "NO2" : "31", "O3_1hour" : "168", "O3_8hour" : "68", "SO2" :"13", "CurrentTime": "ISODate()"})
> db.usercollection.find().pretty()
{
	"_id" : ObjectId("53ba82f97346b7523d951085"),
	"Temperature" : "21.9",
	"DewPoint" : "19.93",
	"Humidity" : "0.89",
	"Pressure" : "1004.85",
	"Ozeone" : "289.03",
	"AQI" : "70",
	"Level" : "良",
	"FirstPollution" : "臭氧1小时",
	"PM2_5" : "51",
	"PM10" : "70",
	"CO" : "0.148",
	"NO2" : "31",
	"O3_1hour" : "168",
	"O3_8hour" : "68",
	"SO2" : "13"
}

We will insert many many records into the database, how to distinguish them? By Timestamp!!!

In MongoDB we have the built-in Function Date():

> Date()
Mon Jul 07 2014 19:29:36 GMT+0800 (CST)

Each inserted Dataset’s timestamp could be fetched out via following command:

> ObjectId("53ba876d7346b7523d951088").getTimestamp()
ISODate("2014-07-07T11:41:33Z")

Next step is using node.js api for processing the dataset.

Display The Inserted Records

We want to display the result like following:

<ul>
    <li>Temperature: 21.9, DewPoint: 19.93, Humidity: 0.89, Pressure: 1004.85, Ozeone: 289.03, AQI: 70, Level: 良, FirstPollution: 臭氧1小时, PM2.5: 51, PM10: 70, CO: 0.148, NO2: 31, O3一小时: 168, O3八小时: 68, So2: 13。 </li>
    <li>Temperature: 21.9, DewPoint: 19.93, Humidity: 0.89, Pressure: 1004.85, Ozeone: 289.03, AQI: 70, Level: 良, FirstPollution: 臭氧1小时, PM2.5: 51, PM10: 70, CO: 0.148, NO2: 31, O3一小时: 168, O3八小时: 68, So2: 13。 </li>
    <li>Temperature: 21.9, DewPoint: 19.93, Humidity: 0.89, Pressure: 1004.85, Ozeone: 289.03, AQI: 70, Level: 良, FirstPollution: 臭氧1小时, PM2.5: 51, PM10: 70, CO: 0.148, NO2: 31, O3一小时: 168, O3八小时: 68, So2: 13。 </li>
</ul>

Change the router/index.js, add following lines:

/* GET weatherlist page. */
router.get('/weatherlist', function(req, res) {
    var db = req.db;
    var collection = db.get('usercollection');
    collection.find({},{},function(e,docs){
        res.render('weatherlist', {
            "weatherlist" : docs
        });
    });
});

Add the new file named weatherlist.jade under views/ folder:

block content
    h1.
        Weather List
    ul
        each weather, i in weatherlist
            li
                首要污染物: #{weather.FirstPollution}, <br />级别: #{weather.Level},<br />AQI: #{weather.AQI},<br />PM2.5: #{weather.PM2_5},<br />PM10: #{weather.PM10}, <br />一氧化碳: #{weather.CO}, <br />二氧化氮: #{weather.NO2}, <br />臭氧一小时浓度: #{weather.O3_1hour}, <br />臭氧八小时浓度: #{weather.O3_8hour}, <br />二氧化硫: #{weather.SO2}, <br />温度: #{weather.Temperature}, <br />露点: #{weather.DewPoint}, <br />湿度: #{weather.Humidity}, <br />气压: #{weather.Pressure}, <br />Ozeone: #{weather.Ozeone}

Now visit http://localhost:3000/weatherlist we could see the record has been listed on the page.

Insert Records In Nodejs

We should use a crontab task for inserting the record once we fetched the data.
The fetching process could be seperated from the web frame, or we could put the script into the directory, and let cron run it, it’s OK.

Following is a sample code for inserting record into mongoDB:

/* 
* This example uses the node MongoDB module to connect to the local
* mongodb database on this virtual machine
*
* More here: http://mongodb.github.io/node-mongodb-native/markdown-docs/insert.html
*/

//require node modules (see package.json)
var MongoClient = require('mongodb').MongoClient
    , format = require('util').format;

//connect away
MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) {
  if (err) throw err;
  console.log("Connected to Database");

  //simple json record
	var document = {name:"David1", title:"About MongoDB1"};
  
	//insert record
	db.collection('test').insert(document, function(err, records) {
		if (err) throw err;
		console.log("Record added as "+records[0]._id);
		//After insertion, close it.
		db.close();
		return;
	});
});

Once fetched, insert into the weathertest Database.

Display How Many Items

It should fetch the latest 24 items from the database, thus we should modify the code for fetching out 24 items.

Edit routes/index.js:

/* GET weatherlist page. */
router.get('/weatherlist', function(req, res) {
    var db = req.db;
    var collection = db.get('usercollection');

    collection.find({},{limit:24},function(e,docs){
        res.render('weatherlist', {
            "weatherlist" : docs
        });
    });

});

Deploy it on heroku

Via following commands we could setup a brand new APP on heroku:

$ heroku login
$ cat web.js
// web.js
var express = require("express");
var logfmt = require("logfmt");
var app = express();

app.use(logfmt.requestLogger());

app.get('/', function(req, res) {
  res.send('Hello World!');
});

var port = Number(process.env.PORT || 5000);
app.listen(port, function() {
  console.log("Listening on " + port);
});
$ npm init
$ npm install express logfmt --save
$ cat package.json
  "engines": {
    "node": "0.10.x"
  }
$ cat Procfile 
web: node web.js
$ foreman start
$ chromium http://localhost:5000
$ git init
$ git add .
$ git commit -m "init"
$ git remote add heroku git@heroku.com:node-weather-app.git
$ git push heroku master

Now visit http://node-weather-app.herokuapp.com you can see “Hello World!".

When adding MongoDB add-ons, it says failed with following information:

$ heroku addons:add mongolab
Adding mongolab on node-weather-app... failed
 !    Please verify your account to install this add-on plan
 !    For more information, see https://devcenter.heroku.com/categories/billing
 !    Verify now at https://heroku.com/verify

Apply the free account athttps://www.mongosoup.de/, then login and create a new database plan, Next time if you want to view your database, simply open your browser and go to https://controlpanel.mongosoup.de/.
Click the Databases, and select the database, then show password, it will shows you with the Database info, something like:

Connection string:	mongodb://############:###########@dbs004.mongosoup.de/cc_KNoBTXxNbHhS

It seems the account failed, so I create a new account using another email, xxxxxxxxxx.
This time the app’s name is named nodeweatherapp git@heroku.com:nodeweatherapp.git
And this time we will use root account for uploading.

    Git URL: git@heroku.com:nodeweather.gi

Proto Thread In Arduino

Recently I want to use RTOS on Arduino, but after reading the material I find it’s not so easy to run another “OS” on Arduino. But I found this library which named “Proto Thread” which could afford me thread-like operation. Following is the steps for using this library for controlling 2 different threads.

Installation of Proto Thread

SMTP Problem Solving

Recently I’ve set up a ticket system, OTRS, which uses smtp for sending out email. It works well in my virtual machine, and in my own server. But when deploying it onto the lab PC, it cannot send out email via smtp. Following is the solving procedure for this problem.

SMTP Server

When Login into the server, following is how to using smtp for sending out email.

$ telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 nxxxxx.xxx.fukcfuck-fugkock.com ESMTP Sendmail 8.14.5+Sun/8.13.3; Thu, 26 Jun 2014 06:43:37 -0500 (CDT)
ehlo localhost
250-nxxxxx.xxx.fukcfuck-fugkock.com Hello localhost [127.0.0.1], pleased to meet you
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-EXPN
250-VERB
250-8BITMIME
250-SIZE
250-DSN
250-ETRN
250-DELIVERBY
250 HELP
mail from: kkkkk@xxxxxx.xx.fugkock.com
250 2.1.0 kkkkk@xxxxxx.xx.fugkock.com... Sender ok
rcpt to:xxx_xxx.mao@fukcfuck-fugkock.com
250 2.1.5 xxx_xxx.mao@fukcfuck-fugkock.com... Recipient ok
data
Subjet:354 Enter mail, end with "." on a line by itself
Hi,
Are you there?
regards,
Admin
.
250 2.0.0 s5QBhbEu014970 Message accepted for delivery
quit
221 2.0.0 xxxxxx.xxx.fukcfuck-fugkock.com closing connection
Connection to localhost closed by foreign host.

Error message

When sending out the /var/log/messages will record the failure message, like:

Jul  1 00:57:10 Linux01 OTRS-CGI-37[2757]: [Info][Kernel::System::CustomerUser::DB::CustomerUserAdd] CustomerUser: '9988@qq.com' created successfully (1)!
Jul  1 00:57:10 Linux01 OTRS-CGI-37[2757]: [Notice][Kernel::System::CustomerUser::DB::SetPassword] CustomerUser: '9988@qq.com' changed password successfully!
Jul  1 00:57:12 Linux01 OTRS-CGI-37[2757]: [Error][Kernel::System::Email::SMTP::Send][Line:139]: Can't send to '9988@qq.com': 5505.7.1 <9988@qq.com>... Relaying denied. IP name lookup failed [104.xxx.xxx.53]#012! Enable Net::SMTP debug for more info!
Jul  1 00:57:12 Linux01 OTRS-CGI-37[2757]: [Info][Kernel::System::Email::Send] Error sending message

It says the IP name lookup failed.

Bug Shooting

Use tcpdump for capturing the package, comparing to the normal package.
It indicates the message “IP name lookup failed [104.xxx.xxx.53]", so I guess this may caused by reverse refer of smtp server.

Use dnslookup for the correct record:

[Trusty@Linux01 ~]$ nslookup 104.xxx.xxx.53
Server:        104.xxx.xxx.xxx
Address:    104.xxx.xxx.xxx#53

** server can't find 53.xxx.xxx.104.in-addr.arpa.: NXDOMAIN

=============================================================


[Trusty@Linux01 ~]$ nslookup 104.xxx.xxx.240
Server:        104.xxx.xxx.xxx
Address:    104.xxx.xxx.xxx#53

Non-authoritative answer:
240.xxx.xxx.104.in-addr.arpa    name = xxxxxxxx.xx.fukcfuck-fugkock.com.

So the solution is quite clear: If we give 104.xxx.xxx.140 a name, we could easily reached this machine from smtp server, thus the problem may be solved.

Turn Joggler into a real Digital Picture Frame

In fact Joggler initially is released as a digital picture frame, but I turned it into a linux server. Now It’s time to turn this server back.

Change RunLevel

Edit the gdm.conf file:

# cat /etc/init/gdm.conf
# gdm - GNOME Display Manager
#
# The display manager service manages the X servers running on the
# system, providing login and auto-login services

description     "GNOME Display Manager"
author          "William Jon McCann <mccann@jhu.edu>"

start on ((filesystem
           and runlevel [!06]
           # Without 03, assume our default level is 03
           #and runlevel [!03]

To known your default run level, type:

# runlevel
N 3

Then reboot the joggler, to see if you could get the gdm window.

Disable auto-logon via:

$ cat /etc/init/tty1.conf
respawn
#exec /sbin/mingetty -8 38400 tty1 Trusty -8 38400 tty1
exec /sbin/getty -8 38400 tty1

Install lightdm via:

$ sudo apt-get install lightdm
$ sudo dpkg-reconfigure lightdm

Enable auto-login to lightdm:

$ cat /etc/lightdm/lightdm.conf 
[SeatDefaults]
autologin-user=Trusty
autologin-user-timeout=0
greeter-session=lightdm-gtk-greeter
user-session=xubuntu

Enable SlideShow

Find out the resolution via following command:

$ xrandr | grep '*'
   800x480        60.0* 

Install essential software:

$ sudo apt-get install feh
$ sudo apt-get install unclutter

In fact using feh is not good enough for setting the screenSaver, at last I use xscreensaver, it has a mode of glslideshow, you can specify your own directory.