Home Automation (part 2)

Note: Part 1 is here

Electrical setup for living room light

Our new place doesn't have any ceiling lights in the living room, but one switch activated wall plug. It is driven by a 2 way setup of 2 switches, and I decided to put the fibaro dimmer in one of them, and replace the standard switch by a push button.

The fibaro dimmer2 has 2 switch inputs, so I took a 2 button ones, and set it up in place of one of the switches, and use a single for the other one.

Currently it works like this:

  • entrance: single switch
  • near tv: double switch
  • single push: light on, same level of dimming as last use, another push to power off
  • double push: light on, full brightness
  • long press: starts at lower power, and slowly rise to allow control of dimming

Using the z-wave grouping, the second switch controls the dimming plug, where I have a floor lamp plugged for now.

Software

First thing first, the usb z-wave dongles are generally seen simplay as usb serial ports, so it will work on almost any system, as long as the software you wan to use runs on it too.

Current setup

I currently plugged the dongle on my NAS, running FreeNAS, in a jail, this caused some issues I'll explain later when detailing the softwares I tested. The computer is an AMD-E350 which is a dual core 1.6GHz, with 8GB of ram.

Likely futur setup

I will probably move the home automation to a separate machine, a lot of people use raspberrypi for this, but I will probably take an odroid-c2, The reason being I do plan on adding voice control, and latency will play a big part in the feeling of it, faster cores will ilkely help a lot in this. We will see.

Testing the softwares

There are various open source options out there to setup your own home automation box:

  • OpenHAB: v1 and v2 (in beta), a pretty huge beast, in java, but very powerful, with a lot of features
  • Domoticz: written in C, it was pretty appealing to me at first (see below)
  • Home-Assistant: written in python, pretty easy to start with
  • Jeedom: opensource but limited if you don't subscribe

I didn't try Jeedom as I wasn't fond of the subscription thing but I did try, or at least try to try, the others.

NOTE: There are other options, I didn't search everything, and didn't had time to try them all, so I only mention the ones I planned to test at first.

OpenHAB

OpenHAB is kinda the go to home automation software, it is well known, well supported, have a lot of features, the version2 has better way to handle things from the UI instead of fiddling with the configuration file, but the issue was that I run FreeBSD/FreeNAS: it comes with packages lib/modules/whatever the java world called them, including the one that handles talking to the serial port.

Unfortunately, there is a bug on FreeBSD with the shipped version, and I didn't dare rebuild everything myself just to patch this lib, so after a while I gave up for now. I still plan to give it a shot if things get easier to get it to work.

If you happen to have more motivation than I and want to try, there is a page about making openhab working on FreeBSD.

Domoticz

Domoticz was the second one I tried, mostly because it is written in C and I felt like it would be easier to fiddle inside it if needed. And I did. I had to fiddle in the code almost straight away, as the USB serial port showed up as /dev/ttyU0 but also as /dev/cuaU0. For some reason, the ifdefs in domoticz code are choosing ttyU for FreeBSD, but on my setup, this one wasn't working, wehereas the cuauU one worked, so I patched it and went with this.

I did set it up, and started using it. One nice thing it had too, is the z-wave network tools, monitongi, inclusion mode etc. That is pretty nice.

I was pretty happy until about 24h later, when for some reason it became pretty slow, like it took about 30 seconds to turn the lights on. So after a quick search, and not finding anything obvious, I went to try another one.

Home Assistant

Home Assistant (HA) is the one I still run today, it is pretty slick, setting it up was fairly easy and I didn't had to patch it. But it requires that you install the python-OpenZWave pacakge, but everything is explained on the getting-started/z-wave page, and it wasn't too hard to do. It has some services about the z-wave network that you can call, but it isn't as integrated as it is in domoticz, I actually didn't had to play with it, as the z-wave itself was already setup at this stage, I simply enable the z-wave component in HA, configured the serial port, and fire it up, and it detected the devices and they worked like a charm.

At first, it is a bit hard to understand what goes where in the configuration, or what the services/stats things in the web-ui are, but once you get a grasp of the basic principles, it is pretty easy to understand, and quite powerful.

Python-lovers will be confortable with the yaml configuration and the use of templates (as in jinja-templates) for some advanced usage.

Let's stop here for this part, the third one will talk about my current HA configuration.


16 juillet 2016 13:32:21 -- tags [ home-automation , z-wave , openhab , domoticz , home-assistant ]

0 Comments

Home Automation begins (part 1)

Introduction

So we moved, again, back to Versailles. I had the bad idea to start looking into home automation before we even moved, and started wondering what I wanted to have or to do.

Defining the need

The thing I was interested in at first was simply controlling the lights, I wanted to be LED based and dimmable. I like LED strips, but 12 or 24v things means you need a converter, and the dimming should be done at this level, which kind of make the controlling remotely in software harder to achieve.

Wandering online I discovered there now are 220v LED strips, you can't cut them anywhere like most 12v, but that was fine by me, so I got a 10m of it, and a few connectors and stuff to go with it.

I then looked at the various protocol used, and pretty quickly found that there currently is more devices available for z-wave and decided I'd go with it.

At first I was about to buy an already made box, and realized there were pretty amazing open source software available and could be installed on a computer or a raspberrypi with an usb dongle.

Looking online, I then realized all the things you could do with the so called Home Automation, and ended up with a kinda crazy goal:

  • light control
  • temperature and humidity monitoring
  • heaters control
  • power consumption monitoring
  • door and windows opening monitoring
  • alarm
  • smoke detector

The biggest drawback on z-wave is its price, every module is expensive, when you sum up all the thing I listed before, the bill was fairly high and I decided to start small instead of getting everything right away.

First order

So I ordered 4 things:

Once I received this and the LED strip, I started playing with it, simply with the plug as we didn't move yet.

It does flicker (the bypass was for the fibaro module, not the plug), but it works, first test was encouraging, first step completed.

Continue to Part 2


15 juillet 2016 12:48:03 -- tags [ home-automation , z-wave , dimmer , dimmable , led ]

0 Comments

Decipher ESP packets with Scapy

I'm currently working on implementing support for hardware cryptographic engine on a board we support at work. Currently it is not working and I was trying to debug it, thus trying to see what is happening. I tcpdumped the packets received, and tried to have a look at it. Sadly, for some reason, the SAs I added in wireshark do not match and he doesn't want to use them.

I then discovered that scapy now has support for that, and it was actually added by a colleague... Should have started there! I only found the issues on bitbucket showing how to use it so I thought it would be worth it to write a quick how-to, once got it down it is pretty straightforward, but knowing what to look for may not be obvious in the first place.

So here is a an example usage for an AES-CBC with no auth packet:

pkts = rdpcap("path/to/file.pcap")
pkts[0].show()

Here is the ESP packet:

###[ Ethernet ]###
  dst= 56:1e:7d:aa:e0:b3
  src= 68:05:ca:15:d1:99
  type= IPv4
###[ IP ]###
     version= 4L
     ihl= 5L
     tos= 0x0
     len= 140
     id= 0
     flags= DF
     frag= 0L
     ttl= 64
     proto= esp
     chksum= 0x2544
     src= 10.125.0.2
     dst= 10.125.0.1
     \options\
###[ ESP ]###
        spi= 0x22
        seq= 1
        data= '\xa7\[...]'

Then create the SA and decrypt:

sa = SecurityAssociation(ESP, spi=0x22, crypt_algo='AES-CBC', crypt_key='your_key')
res = sa.decrypt(pkts[0].getlayer(IP))
res.show()

The result showing the icmp packet:

###[ IP ]###
  version= 4L
  ihl= 5L
  tos= 0x0
  len= 104
  id= 0
  flags= DF
  frag= 0L
  ttl= 64
  proto= ipv4
  chksum= 0x2596
  src= 10.125.0.2
  dst= 10.125.0.1
  \options\
###[ IP ]###
     version= 4L
     ihl= 5L
     tos= 0x0
     len= 84
     id= 36470
     flags= DF
     frag= 0L
     ttl= 63
     proto= icmp
     chksum= 0x9805
     src= 10.200.0.1
     dst= 10.100.0.1
     \options\
###[ ICMP ]###
        type= echo-request
        code= 0
        chksum= 0x7cd1
        id= 0x9df
        seq= 0x1
###[ Raw ]###
       load= '\x9fTMW[...]'

And here you go.


31 mai 2016 13:35:34 -- tags [ scapy , python , IPsec , cipher , crypto ]

0 Comments

.vimrc

As a reference, here is my current .vimrc file, stripped from a few things specific to my current job:

" ---------------
" Start Plug
" ---------------
call plug#begin('~/.vim/plugged')

" git
Plug 'tpope/vim-fugitive'

" utils
Plug 'rking/ag.vim'         " ag fro grepping in vim
Plug 'tpope/vim-commentary' " gcc gc etc for commenting
Plug 'tpope/vim-surround'   " change surrounding chars
Plug 'tpope/vim-unimpaired' " [<space> and more
Plug 'tpope/vim-sensible'   " default settings that makes sense
"Plug 'tpope/vim-rsi'        " shell/emacs binding in insert mode
Plug 'tpope/vim-tbone'      " tmux integration in vim
Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' }
Plug 'junegunn/fzf.vim'

" wiki + tw
Plug 'vimwiki/vimwiki'
Plug 'tbabej/taskwiki'

" appearance
Plug 'powerline/powerline'
Plug 'noah/fu'

" Add plugins to &runtimepath
call plug#end()

" ---------------
" Behavior
" ---------------
syntax on
set nobackup
set undodir=~/etc/vim/undo
set history=1000
set undolevels=1000
set wildignore=*.swp,*.bak,*.pyc,*.class
set hidden " allow changing buffer from unsaved

set ai
set cinoptions=(0
set cindent
set nocompatible
set ruler
set hlsearch
set wildmode=list:longest "bash like completion

set mouse=vn
set clipboard=unnamed

filetype plugin on
if has("autocmd")
  autocmd BufRead *.txt set tw=78 sw=2 ts=2 et
  autocmd BufRead *.py set tw=80 sw=4 ts=4 et
  autocmd BufRead *.sh set ts=4 sw=4 et noai nocin
  autocmd Bufread *.wiki set tw=80 ts=4 sw=4 et ai
endif

" spellcheck in rst
autocmd FileType rst setlocal spell spelllang=en_us
autocmd Filetype rst set tw=80 sw=2 ts=2 et

" ---------------
" Appearance
" ---------------
set term=xterm-256color
set t_Co=256
set background=dark
set listchars=tab:▸\ ,eolcolorscheme fu

set laststatus=2
set cursorline
set nocursorcolumn
set colorcolumn=80
highlight ColorColumn ctermbg=16
highlight CursorLine ctermbg=23 term=bold cterm=bold

" Syntax error hilighting, this should be after colorscheme
syntax match Error "\(^\t.*\n\)\@<= \+"
syntax match Error "\(^ \+.*\n\)\@<=\t\+"
autocmd FileType c* syntax match Error '\%>80v.\+'

" enable powerline
set rtp+=/home/bleader/.vim/plugged/powerline/powerline/bindings/vim

" enable fzf
set rtp+=~/.fzf

" ---------------
" Binds
" ---------------

" use , for map leader, feel easier than \
let mapleader=","

set pastetoggle=<F9>

" edit/reload vimrc quickly
nmap <silent> <leader>ev :e $MYVIMRC<CR>
nmap <silent> <leader>sv :so $MYVIMRC<CR>

" allow use of ; in place of :
nnoremap ; :

" clear search hilight
nmap <silent> <leader>/ :nohl<CR>

" Error list binds
nnoremap <leader>n :cn<CR>zz
nnoremap <leader>p :cp<CR>zz

" compute line through rcpy https://github.com/bleader/rcpy
map <F4> yypV:!rcpy<CR>

" enable/disable list
imap <F1> <C-o>:set nolist!<CR>
map <F1> <ESC>:set nolist!<CR>

" moving around centering
nnoremap n nzz
nnoremap N Nzz
nnoremap * *zz
nnoremap # #zz
nnoremap g* g*zz
nnoremap g# g#zz
nnoremap [[ [[zz
nnoremap ]] ]]zz
nnoremap {{ {{zz
nnoremap }} }}zz

" debug printf in C
map <leader>dd oprintf("%s:%d\n", __func__, __LINE__);<Esc>==

" paste selection to haste
vnoremap Y <esc>:'<,'>:w !haste<CR>

" ---------------
" GIT
" ---------------
nnoremap <leader>gd :Gvdiff<CR>
nnoremap <leader>gs :Gstatus<CR>
nnoremap <leader>gl :Glog --<CR>:copen<CR>
nnoremap <leader>gL :Git l<CR>
nnoremap <leader>gg :Ggrep <cword><CR>
nnoremap <leader>ag :Ag <cword><CR>
nnoremap <leader>gc :Gcommit -s -v<CR>
nnoremap <leader>gS :Git show<CR>
nnoremap <leader><leader>gS :Git show <cword><CR>
autocmd BufReadPost fugitive://* set bufhidden=delete

let g:git_branch_status_head_current=1 
let g:git_branch_status_text="branch "
let g:git_branch_status_nogit="no git"
let g:git_branch_status_around="{}"

fu! GitReview()
    Glog --reverse origin/master.. -- .
    copen
endf
command Greview call GitReview()
nnoremap <leader>gr :Greview<CR>

" ---------------
" Cscope bindings and configuration (autoload of cscope.out)
" ---------------
nmap <leader>cs :cs find s <C-R>=expand("<cword>")<CR><CR>
nmap <leader><leader>cs :vert scs find s <C-R>=expand("<cword>")<CR><CR>
nmap <leader>cg :cs find g <C-R>=expand("<cword>")<CR><CR>
nmap <leader><leader>cg :vert scs find g <C-R>=expand("<cword>")<CR><CR>
nmap <leader>cc :cs find c <C-R>=expand("<cword>")<CR><CR>
nmap <leader><leader>cc :vert scs find c <C-R>=expand("<cword>")<CR><CR>
nmap <leader>ct :cs find t <C-R>=expand("<cword>")<CR><CR>
nmap <leader><leader>ct :vert scs find t <C-R>=expand("<cword>")<CR><CR>
nmap <leader>ce :cs find e <C-R>=expand("<cword>")<CR><CR>
nmap <leader><leader>ce :vert scs find e <C-R>=expand("<cword>")<CR><CR>
nmap <leader>cf :cs find f <C-R>=expand("<cfile>")<CR><CR>
nmap <leader><leader>cf :vert scs find f <C-R>=expand("<cfile>")<CR><CR>
nmap <leader>ci :cs find i ^<C-R>=expand("<cfile>")<CR>$<CR>
nmap <leader><leader>ci :vert scs find i ^<C-R>=expand("<cfile>")<CR>$<CR>
nmap <leader>cd :cs find d <C-R>=expand("<cword>")<CR><CR>
nmap <leader><leader>cd :vert scs find d <C-R>=expand("<cword>")<CR><CR>

if has("cscope") && filereadable("/usr/bin/cscope")
   set csprg=/usr/bin/cscope
   set csto=0
   set cst
   set nocsverb
   " add any database in current directory
   if filereadable("cscope.out")
      cs add cscope.out
   " else add database pointed to by environment
   elseif $CSCOPE_DB != ""
      cs add $CSCOPE_DB
   endif
   set csverb
endif

fu! CscopeReload()
   cscope kill 0
   !cscope -R -b
   cscope add cscope.out
endf

nmap <leader>cR :call CscopeReload()<CR>

" edit .configs
map <leader>uu ^i# <esc>$xxA is not set<esc>
map <leader>ss ^xxEld$a=y<esc>

" FZF
let g:fzf_command_prefix="Fzf"
nnoremap <leader>f :FzfFiles<cr>
nnoremap <leader>b :FzfBuffers<cr>
inoremap <expr> <c-x><c-k> fzf#vim#complete#word({'left': '15%'})

30 décembre 2015 13:26:14 -- tags [ vim , configuration ]

0 Comments

Review git-to-be-pushed changes in vim

First, this assume you use fugitive.vim. You don't? I really think you should. If you're still not convinced, have a quick look at the readme, take some time to go over one of the screencast linked there. I personally understood a lot about git index by watching the screencast Working with the git index.

I personnally like to have a look at my patches before giving them to my colleagues, there are a lot of options available to achieve this:

  • starting a gitweb
  • git log -p
  • git show of each commits
  • using tig
  • using fugitive directly in vim

As you may have guessed, my favorite is the last one, for this, I use a small function plus a bind:

fu! GitReview()                                                                 
        Glog --reverse origin/master.. -- .                                     
        copen                                                                   
endf                                                                            
command Greview call GitReview()                                                
nnoremap <leader>gr :Greview<CR>

This creates the GitReview() function, allows you to call it via :Greview or by the bind gr.

It will do a fugitive :Glog from the head of your current branch to origin/master and show it in reverse order so you start on the first commit after origin/master. This could be improved to do it based on the remotely tracked branch or accept a parameter to specify which branch to start from.

Once you called this, the first patch will be opened, likely with each files touched by the patch folded so you can review them one by one if you want. Following patches are loaded in the quickfixlist, that will likely have opened at the bottom of your vim. If you are not familiar with the quickfix list you can always :h quickfix. Thing to know, you can move forward and backward in this list be it shown or hidden, with :cn and :cp (Next/Prev).

And that's about it for this one. Hope it can be useful to someone!


30 décembre 2015 13:15:28 -- tags [ vim , git , fugitive , tips ]

0 Comments

Git command typos

Recently beorn shared two git typos on IRC, and I felt it was worth a small post about possible typos and their possible meaning, if any.

add

git ass

For when you need to get some?

bisect

git insect

Ok, this one may be a little far-fetched... still, it il likely you're searching for a bug, aren't you?

commit

git vommit

That one is for when you know your code is really dirty. (you better cleanup before pushing)

diff

git duff

At this stage, its time for a beer. Oh, yeah!

log

git lag

Maybe too much git duff, or you are just checking how far behing origin/master you are.

pull

git pill

Will you take the red or the blue pill?

push

git pish

After some git duff you'll have to take a pish, that is how it goes.

show

git dhow

Doh'! You are about to check how this commit looks like now that you've sober up, not feeling good about it, eh?

status

git statue

Just having a look at the greatness of what you're actually building, that was worth the efforts!

tag

git tab

Better keep an eye on your tab at Moe's, and make sure Barney hasn't been ordering on your tab.

That's about it, looking at a keyboard, other commands didn't gave me any idea, some are already quite far-fetched and may not have ended up in here, but here they are.


29 octobre 2013 18:41:40 -- tags [ git , command , typos , fun ]

0 Comments

Imagemagick convert and groups

I was willing to make some combined images to show off Camille Dolls, but I wanted to have good alignement and spacing between the pictures. I gave a shot at doing it by hand with Gimp but making alignement and spacing by hand was kind of a hassle. I'm pretty sure I missed some features which may have made it easier, but I decided to search another solution. Scribus seems to be made for this kind of things, but tends to be restrictive toward the final output given its main purpose being to design final paper documents.i

In the end, I decided to play with convert and other Imagemagick tools, which proved quite efficient once I got the grasp of groups.

When issuing a convert command for example, you can group set of option and they will be treated like an image. This allows more flexibility in the order to achieve your final result in less command and without, or with less intermediate images.

To stack 2 pictures on top of each other with a 10 pixels separation and a 10 pixels border around the whole thing, the steps are:

  • take first image
  • extent it by its height + 10
  • take second image
  • stack them
  • add border to whole thing

A useful command is identify which can give you output information about an image, and allows calculations to be done, to get the height + 10:

identify -format 'x%[fx:H+10]' in.png

To group commands in convert you put them between parenthesis, that needs to be escaped so your shell don't interpret them:

convert \( \( command1 \) \( command2 \) \) command_on_result out.png

So for our example:

img1=A.png
img2=B.png
convert \
    \( \ # group for resulting images stacked
        \( $img1 -extent $(identify -format 'x%[fx:H+10]' $img1) \) \ # take first pic and add 10px
        $img2 \
    \) \
    -append # stack images
    -border 10x10 \ # add border around stacked images
    out.png

A more complete thing I did was stack 2 pictures on the left, for a total of 800px, and then add another picture of 800px on the right, so to achieve this:

  • resize first picture to 395px height
  • add 10px space
  • resize the second picture to 395px height
  • stack them
  • add 10px to width to the result, you need to know the width of the resized images
  • add last picture to the right
  • add border

In term of convert:

convert \( \
  \( \
    \( -geometry x395 img1.png -extent x405 \) \ # resize + add 10px margin
    img2.png  -append \
  \) -extent 405x \ # add 10px to width
  img3.png
  \) +append \
  -border 10x10 \
  out.png

I hope this can be of some help to someone, you can check out my results.


29 juin 2013 00:22:48 -- tags [ imagemagick , convert , groups , images , combine , identify , convert ]

8 Comments

Homemade Gyozas

Today I finally decided to take a shot at making Gyozas, they could have looked better, but they were absolutely delicious...


7 juin 2013 23:47:13 -- tags [ food , cooking , gyoza , japanese ]

0 Comments

Marker Beacon album release: Dead Frequencies

Changing topic a bit, a friend and colleague has his band releasing their album today:

Marker Beacon - Dead Frequencies

The album is released under Creative Commons licence and can be downloaded and streamed directly from their website, and you can by the pressed CD from their shop

Enjoy!


3 juin 2013 23:39:33 -- tags [ Metal , Music ]

0 Comments

Irssi Window Change Bindings

EDIT: Urxvt has a bind on meta-s so I had to add to my .Xdefaults:

URxvt.searchable-scrollback: CM-s

I've using the default window change key bindings in irssi for a long time, plus some aliasse like

alias 30 /window 30

But I've had an idea recently by reading a piece of the /help bind output

 /BIND ^W^C /WINDOW NEW HIDE
 /BIND ^W^K /WINDOW KILL

But maybe you wish to give these binds to other people who want to use some
other key than ^W, then it would be better done as:

 /BIND ^W key window
 /BIND window-^C /WINDOW NEW HIDE
 /BIND window-^K /WINDOW KILL

I thought that to reduce motion and have a somewhat more fluent feeling for changing windows I should find a set of prefix followed by a simple set of keys. I decided to use meta modifier, and to prefix the 'number' by the index keys for each level. I'm using a dvorak layout:

1 2 3 4 5   6 7 8 9 0 
' , . p y   f g c r l
a o e u i   d h t n s
; q j k x   b m w v z
              ^

And I used the order that I'm the most confortable with:

meta-h  (0-20)
meta-m  (21-40)
meta-g  (41-60)
meta-7  (61-80)

So for each of these I add a named bind just like in the help section, here is a snippet in my .irssi/config:

{ key = "meta-h"; id = "key"; data = "win0"; },
{ key = "meta-m"; id = "key"; data = "win1"; },
{ key = "meta-g"; id = "key"; data = "win2"; },
{ key = "meta-7"; id = "key"; data = "win3"; },

I am using keys in an odd order to follow the ease of access of the keys, keeping meta pressed:

  • first the home key h t n s and then the shifted index key d (1 2 3 4 5)
  • then the bottom row: m w v z b (6 7 8 9 10)
  • above the home keys: g c r l f (11 12 13 14 15)
  • top row: 7 8 9 0 6 (16 17 18 19 20)

Each of the previously explained prefixes are used as multipliers for these numbers, allowing direct bind access for up to 80 windows.

For example, some examples:

/window 25
meta-m meta-d (prefix win1 -> and 5, here d)

/window 40
meta-m meta-6

It takes some time to get used to it, but has a nice feeling to it once into you get you muscle memory into it. Following is the full configuration for dvorak and qwerty layout.

Dvorak

{ key = "meta-h"; id = "key"; data = "win0"; },
{ key = "win0-meta-h"; id = "change_window"; data = "1"; },
{ key = "win0-meta-t"; id = "change_window"; data = "2"; },
{ key = "win0-meta-n"; id = "change_window"; data = "3"; },
{ key = "win0-meta-s"; id = "change_window"; data = "4"; },
{ key = "win0-meta-d"; id = "change_window"; data = "5"; },
{ key = "win0-meta-m"; id = "change_window"; data = "6"; },
{ key = "win0-meta-w"; id = "change_window"; data = "7"; },
{ key = "win0-meta-v"; id = "change_window"; data = "8"; },
{ key = "win0-meta-z"; id = "change_window"; data = "9"; },
{ key = "win0-meta-b"; id = "change_window"; data = "10"; },
{ key = "win0-meta-g"; id = "change_window"; data = "11"; },
{ key = "win0-meta-c"; id = "change_window"; data = "12"; },
{ key = "win0-meta-r"; id = "change_window"; data = "13"; },
{ key = "win0-meta-l"; id = "change_window"; data = "14"; },
{ key = "win0-meta-f"; id = "change_window"; data = "15"; },
{ key = "win0-meta-7"; id = "change_window"; data = "16"; },
{ key = "win0-meta-8"; id = "change_window"; data = "17"; },
{ key = "win0-meta-9"; id = "change_window"; data = "18"; },
{ key = "win0-meta-0"; id = "change_window"; data = "19"; },
{ key = "win0-meta-6"; id = "change_window"; data = "20"; },

{ key = "meta-m"; id = "key"; data = "win1"; },
{ key = "win1-meta-h"; id = "change_window"; data = "21"; },
{ key = "win1-meta-t"; id = "change_window"; data = "22"; },
{ key = "win1-meta-n"; id = "change_window"; data = "23"; },
{ key = "win1-meta-s"; id = "change_window"; data = "24"; },
{ key = "win1-meta-d"; id = "change_window"; data = "25"; },
{ key = "win1-meta-m"; id = "change_window"; data = "26"; },
{ key = "win1-meta-w"; id = "change_window"; data = "27"; },
{ key = "win1-meta-v"; id = "change_window"; data = "28"; },
{ key = "win1-meta-z"; id = "change_window"; data = "29"; },
{ key = "win1-meta-b"; id = "change_window"; data = "30"; },
{ key = "win1-meta-g"; id = "change_window"; data = "31"; },
{ key = "win1-meta-c"; id = "change_window"; data = "32"; },
{ key = "win1-meta-r"; id = "change_window"; data = "33"; },
{ key = "win1-meta-l"; id = "change_window"; data = "34"; },
{ key = "win1-meta-f"; id = "change_window"; data = "35"; },
{ key = "win1-meta-7"; id = "change_window"; data = "36"; },
{ key = "win1-meta-8"; id = "change_window"; data = "37"; },
{ key = "win1-meta-9"; id = "change_window"; data = "38"; },
{ key = "win1-meta-0"; id = "change_window"; data = "39"; },
{ key = "win1-meta-6"; id = "change_window"; data = "40"; },

{ key = "meta-g"; id = "key"; data = "win2"; },
{ key = "win2-meta-h"; id = "change_window"; data = "41"; },
{ key = "win2-meta-t"; id = "change_window"; data = "42"; },
{ key = "win2-meta-n"; id = "change_window"; data = "43"; },
{ key = "win2-meta-s"; id = "change_window"; data = "44"; },
{ key = "win2-meta-d"; id = "change_window"; data = "45"; },
{ key = "win2-meta-m"; id = "change_window"; data = "46"; },
{ key = "win2-meta-w"; id = "change_window"; data = "47"; },
{ key = "win2-meta-v"; id = "change_window"; data = "48"; },
{ key = "win2-meta-z"; id = "change_window"; data = "49"; },
{ key = "win2-meta-b"; id = "change_window"; data = "50"; },
{ key = "win2-meta-g"; id = "change_window"; data = "51"; },
{ key = "win2-meta-c"; id = "change_window"; data = "52"; },
{ key = "win2-meta-r"; id = "change_window"; data = "53"; },
{ key = "win2-meta-l"; id = "change_window"; data = "54"; },
{ key = "win2-meta-f"; id = "change_window"; data = "55"; },
{ key = "win2-meta-7"; id = "change_window"; data = "56"; },
{ key = "win2-meta-8"; id = "change_window"; data = "57"; },
{ key = "win2-meta-9"; id = "change_window"; data = "58"; },
{ key = "win2-meta-0"; id = "change_window"; data = "59"; },
{ key = "win2-meta-6"; id = "change_window"; data = "60"; },

{ key = "meta-7"; id = "key"; data = "win3"; },
{ key = "win3-meta-h"; id = "change_window"; data = "61"; },
{ key = "win3-meta-t"; id = "change_window"; data = "62"; },
{ key = "win3-meta-n"; id = "change_window"; data = "63"; },
{ key = "win3-meta-s"; id = "change_window"; data = "64"; },
{ key = "win3-meta-d"; id = "change_window"; data = "65"; },
{ key = "win3-meta-m"; id = "change_window"; data = "66"; },
{ key = "win3-meta-w"; id = "change_window"; data = "67"; },
{ key = "win3-meta-v"; id = "change_window"; data = "68"; },
{ key = "win3-meta-z"; id = "change_window"; data = "69"; },
{ key = "win3-meta-b"; id = "change_window"; data = "70"; },
{ key = "win3-meta-g"; id = "change_window"; data = "71"; },
{ key = "win3-meta-c"; id = "change_window"; data = "72"; },
{ key = "win3-meta-r"; id = "change_window"; data = "73"; },
{ key = "win3-meta-l"; id = "change_window"; data = "74"; },
{ key = "win3-meta-f"; id = "change_window"; data = "75"; },
{ key = "win3-meta-7"; id = "change_window"; data = "76"; },
{ key = "win3-meta-8"; id = "change_window"; data = "77"; },
{ key = "win3-meta-9"; id = "change_window"; data = "78"; },
{ key = "win3-meta-0"; id = "change_window"; data = "79"; },
{ key = "win3-meta-6"; id = "change_window"; data = "80"; },

Qwerty

Layout extract:

12345 67890
qwert yuiop
asdfg hjkl;
zxcvb nm,./

Configuration (untested):

{ key = "meta-j"; id = "key"; data = "win0"; },
{ key = "win0-meta-j"; id = "change_window"; data = "1"; },
{ key = "win0-meta-k"; id = "change_window"; data = "2"; },
{ key = "win0-meta-l"; id = "change_window"; data = "3"; },
{ key = "win0-meta-;"; id = "change_window"; data = "4"; },
{ key = "win0-meta-h"; id = "change_window"; data = "5"; },
{ key = "win0-meta-m"; id = "change_window"; data = "6"; },
{ key = "win0-meta-,"; id = "change_window"; data = "7"; },
{ key = "win0-meta-."; id = "change_window"; data = "8"; },
{ key = "win0-meta-/"; id = "change_window"; data = "9"; },
{ key = "win0-meta-n"; id = "change_window"; data = "10"; },
{ key = "win0-meta-u"; id = "change_window"; data = "11"; },
{ key = "win0-meta-i"; id = "change_window"; data = "12"; },
{ key = "win0-meta-o"; id = "change_window"; data = "13"; },
{ key = "win0-meta-p"; id = "change_window"; data = "14"; },
{ key = "win0-meta-y"; id = "change_window"; data = "15"; },
{ key = "win0-meta-7"; id = "change_window"; data = "16"; },
{ key = "win0-meta-8"; id = "change_window"; data = "17"; },
{ key = "win0-meta-9"; id = "change_window"; data = "18"; },
{ key = "win0-meta-0"; id = "change_window"; data = "19"; },
{ key = "win0-meta-6"; id = "change_window"; data = "20"; },

{ key = "meta-m"; id = "key"; data = "win1"; },
{ key = "win0-meta-j"; id = "change_window"; data = "21"; },
{ key = "win0-meta-k"; id = "change_window"; data = "22"; },
{ key = "win0-meta-l"; id = "change_window"; data = "23"; },
{ key = "win0-meta-;"; id = "change_window"; data = "24"; },
{ key = "win0-meta-h"; id = "change_window"; data = "25"; },
{ key = "win0-meta-m"; id = "change_window"; data = "26"; },
{ key = "win0-meta-,"; id = "change_window"; data = "27"; },
{ key = "win0-meta-."; id = "change_window"; data = "28"; },
{ key = "win0-meta-/"; id = "change_window"; data = "29"; },
{ key = "win0-meta-n"; id = "change_window"; data = "30"; },
{ key = "win0-meta-u"; id = "change_window"; data = "31"; },
{ key = "win0-meta-i"; id = "change_window"; data = "32"; },
{ key = "win0-meta-o"; id = "change_window"; data = "33"; },
{ key = "win0-meta-p"; id = "change_window"; data = "34"; },
{ key = "win0-meta-y"; id = "change_window"; data = "35"; },
{ key = "win0-meta-7"; id = "change_window"; data = "36"; },
{ key = "win0-meta-8"; id = "change_window"; data = "37"; },
{ key = "win0-meta-9"; id = "change_window"; data = "38"; },
{ key = "win0-meta-0"; id = "change_window"; data = "39"; },
{ key = "win0-meta-6"; id = "change_window"; data = "40"; },

{ key = "meta-u"; id = "key"; data = "win2"; },
{ key = "win0-meta-j"; id = "change_window"; data = "41"; },
{ key = "win0-meta-k"; id = "change_window"; data = "42"; },
{ key = "win0-meta-l"; id = "change_window"; data = "43"; },
{ key = "win0-meta-;"; id = "change_window"; data = "44"; },
{ key = "win0-meta-h"; id = "change_window"; data = "45"; },
{ key = "win0-meta-m"; id = "change_window"; data = "46"; },
{ key = "win0-meta-,"; id = "change_window"; data = "47"; },
{ key = "win0-meta-."; id = "change_window"; data = "48"; },
{ key = "win0-meta-/"; id = "change_window"; data = "49"; },
{ key = "win0-meta-n"; id = "change_window"; data = "50"; },
{ key = "win0-meta-u"; id = "change_window"; data = "51"; },
{ key = "win0-meta-i"; id = "change_window"; data = "52"; },
{ key = "win0-meta-o"; id = "change_window"; data = "53"; },
{ key = "win0-meta-p"; id = "change_window"; data = "54"; },
{ key = "win0-meta-y"; id = "change_window"; data = "55"; },
{ key = "win0-meta-7"; id = "change_window"; data = "56"; },
{ key = "win0-meta-8"; id = "change_window"; data = "57"; },
{ key = "win0-meta-9"; id = "change_window"; data = "58"; },
{ key = "win0-meta-0"; id = "change_window"; data = "59"; },
{ key = "win0-meta-6"; id = "change_window"; data = "60"; },

{ key = "meta-7"; id = "key"; data = "win3"; },
{ key = "win0-meta-j"; id = "change_window"; data = "61"; },
{ key = "win0-meta-k"; id = "change_window"; data = "62"; },
{ key = "win0-meta-l"; id = "change_window"; data = "63"; },
{ key = "win0-meta-;"; id = "change_window"; data = "64"; },
{ key = "win0-meta-h"; id = "change_window"; data = "65"; },
{ key = "win0-meta-m"; id = "change_window"; data = "66"; },
{ key = "win0-meta-,"; id = "change_window"; data = "67"; },
{ key = "win0-meta-."; id = "change_window"; data = "68"; },
{ key = "win0-meta-/"; id = "change_window"; data = "69"; },
{ key = "win0-meta-n"; id = "change_window"; data = "70"; },
{ key = "win0-meta-u"; id = "change_window"; data = "71"; },
{ key = "win0-meta-i"; id = "change_window"; data = "72"; },
{ key = "win0-meta-o"; id = "change_window"; data = "73"; },
{ key = "win0-meta-p"; id = "change_window"; data = "74"; },
{ key = "win0-meta-y"; id = "change_window"; data = "75"; },
{ key = "win0-meta-7"; id = "change_window"; data = "76"; },
{ key = "win0-meta-8"; id = "change_window"; data = "77"; },
{ key = "win0-meta-9"; id = "change_window"; data = "78"; },
{ key = "win0-meta-0"; id = "change_window"; data = "79"; },
{ key = "win0-meta-6"; id = "change_window"; data = "80"; },

1 juin 2013 23:57:22 -- tags [ irssi , bind , touch tying ]

1 Comments