Sunday 8 December 2019

Setting Up a Local Streaming Server

Ingredients

minidlnad
icecast2
ezstream
update-ezstream
ice2chrome

Description

minidlnad is a program to serve media files via DLNA protocols

icecast2 is the actual server that clients connect to to stream music

ezstream is the application which supplies media files to the icecast2 server

update-ezstream is an application which forces ezstream to re-read its source media files

ice2chrome is an application which pushes the icecast2 stream to a chromecast receiver

Method

Minidlnad Configuration

A modified version of minidlna can be found at www.vizier.uk.  This version supports configurable layouts.

[config]
unknown=Unknown
searchdepth=4
strippath=/disk/media/Media
[replace]
genre=language courses=audiobook
genre=podcast=audiobook
genre=speech=audiobook
genre=blues-rock=blues
genre=books + spoken=audiobook
genre=international=pop-rock
genre=pop/rock=pop-rock
artist=Jean Michel Jarre=Jean-Michel Jarre
artist=r -e-m=Rem
artist=r-e-m=Rem
[rule]
comment=Ignore Index Tracks for Audiobooks etc
chainset=none
mediatype=audio
or=genre=vocal,genre=radio,genre=audiobook
and=comment=index
[rule]
chainset=audiobook
mediatype=audio
or=genre=audiobook
[rule]
chainset=radio
mediatype=audio
or=genre=radio
[rule]
chainset=legacyradio
mediatype=audio
or=genre=vocal
[rule]
chainset=musicindex
mediatype=audio
and=comment=index
[rule]
chainset=music
mediatype=audio
[rule]
chainset=video
mediatype=video
[rule]
chainset=image
mediatype=image
[rule]
chainset=catchall
[catchall]
chain=/Catchall/$TITLE
[image]
chain=/Folder/$PATH/$FILENAME
chain=/Photo/Location/$LOCNSEW/ - All Photos - /$TITLE
chain=/Photo/Location/$LOCNSEW/$YEAR/$TITLE
chain=/Photo/Date/$DECADE/ - All Photos - /$TITLE
chain=/Photo/Date/$DECADE/$YEAR/$TITLE
chain=/Photo/ - All Photos - /$TITLE
[video]
chain=/Folder/$PATH/$FILENAME
chain=/Video/Date/$DECADE/ - All Videos - /$FILEBASE
chain=/Video/Date/$DECADE/$YEAR/$FILEBASE
chain=/Video/ - All Videos - /$FILEBASE
[music]
chain=/Folder/$PATH/$FILENAME
chain=/Music/Track/ - All Tracks - /$TITLE
chain=/Music/Track/$ABCTITLE/$TITLE
chain=/Music/Album/ - All Albums - /$ALBUM/$TRACKNUM. $TITLE
chain=/Music/Album/$ABCALBUM/$ALBUM/$TRACKNUM. $TITLE
chain=/Music/Artist/ - All Artists - /$ARTIST/By Album/$SALBUM - $TRACKNUM. $TITLE
chain=/Music/Artist/ - All Artists - /$ARTIST/Shuffle/$RND. $TITLE
chain=/Music/Artist/$ABCARTIST/$ARTIST/By Album/$SALBUM - $TRACKNUM. $TITLE
chain=/Music/Artist/$ABCARTIST/$ARTIST/Shuffle/$RND. $TITLE ($SALBUM)
chain=/Music/Date/$DECADE/$YEAR/$TITLE
chain=/Music/Date/$DECADE/ - All Tracks - /$TITLE
chain=/Genre/$GENRE/Track/ - All Tracks - /$TITLE
chain=/Genre/$GENRE/Track/$ABCTITLE/$TITLE
chain=/Genre/$GENRE/Album/ - All Albums - /$ALBUM/$TRACKNUM. $TITLE
chain=/Genre/$GENRE/Album/$ABCALBUM/$ALBUM/$TRACKNUM. $TITLE
chain=/Genre/$GENRE/Artist/ - All Artists - /$ARTIST/By Album/$SALBUM - $TRACKNUM. $TITLE
chain=/Genre/$GENRE/Artist/ - All Artists - /$ARTIST/Shuffle/$RND. $TITLE
chain=/Genre/$GENRE/Artist/$ABCARTIST/$ARTIST/By Album/$SALBUM - $TRACKNUM. $TITLE
chain=/Genre/$GENRE/Artist/$ABCARTIST/$ARTIST/Shuffle/$RND. $TITLE ($SALBUM)
chain=/Genre/$GENRE/Date/$DECADE/$YEAR/$TITLE
chain=/Genre/$GENRE/Date/$DECADE/ - All Tracks - /$TITLE
chain=/Search/Music/$SEARCHALBUMARTIST/$TITLE
chain=/Search/Music/$SEARCHCOMPOSER/$TITLE
chain=/Search/Music/$SEARCHALBUM/$TITLE
chain=/Search/Music/$SEARCHTITLE/$TITLE
 
[musicindex]
chain=/Folder/$PATH/$FILENAME
chain=/Music/Album/ - All Albums - /$ALBUM/$TRACKNUM. $TITLE
chain=/Music/Album/$ABCALBUM/$ALBUM/$TRACKNUM. $TITLE
chain=/Genre/$GENRE/Album/ - All Albums - /$ALBUM/$TRACKNUM. $TITLE
chain=/Genre/$GENRE/Album/$ABCALBUM/$ALBUM/$TRACKNUM. $TITLE
[audiobook]
chain=/Folder/$PATH/$FILENAME
chain=/Audiobook/Author/ - All Authors - /$ARTIST/$ALBUM/$0TRACKNUM. $TITLE
chain=/Audiobook/Author/$ABCARTIST/$ALBUM/$0TRACKNUM. $TITLE
chain=/Audiobook/Book/ - All Titles - /$ALBUM/$0TRACKNUM. $TITLE
chain=/Audiobook/Book/$ABCALBUM/$ALBUM/$0TRACKNUM. $TITLE
chain=/Search/Audiobook Book Title/$SEARCHALBUM/$ALBUM/$0TRACKNUM. $TITLE
chain=/Search/Audiobook Author/$SEARCHARTIST/$ARTIST/$ALBUM/$0TRACKNUM. $TITLE
chain=/Search/Audiobook Author/$SEARCHCOMPOSER/$0TRACKNUM. $TITLE
chain=/Search/Audiobook Chapter/$SEARCHALBUM/$ALBUM/$0TRACKNUM. $TITLE
[radio]
chain=/Folder/$PATH/$FILENAME
chain=/Radio/ - All Programmes - /$ALBUMARTIST/$ALBUM/$0TRACKNUM. $TITLE
chain=/Radio/$ABCALBUMARTIST/$ALBUMARTIST/ - All Series - /$0TRACKNUM. $TITLE
chain=/Radio/$ABCALBUMARTIST/$ALBUMARTIST/$ALBUM/$0TRACKNUM. $TITLE
chain=/Search/Radio Programme/$SEARCHALBUMARTIST/$ALBUMARTIST/$0TRACKNUM. $TITLE
chain=/Search/Radio Episode/$SEARCHTITLE/$0TRACKNUM. $TITLE

Icecast Configuration

Install standard icecast2, and make the following modifications:

/etc/icecast2/icecast.xml
<authentication>
  <source-password>PASS1234</source-password>
  <relay-password>PASS1234</relay-password>
  <admin-user>admin</admin-user>
  <admin-password>ADMINPASS</admin-password>
  </authentication>
<hostname>SERVERNAME</hostname>
<listen-socket>
  <port>8000</port>
  <shoutcast-mount>/channel1</shoutcast-mount>
  <shoutcast-mount>/channel2</shoutcast-mount>
  <shoutcast-mount>/channel3</shoutcast-mount>
  <shoutcast-mount>/channel4</shoutcast-mount>
  <shoutcast-mount>/channel5</shoutcast-mount>
  <shoutcast-mount>/channel6</shoutcast-mount>
  <shoutcast-mount>/channel7</shoutcast-mount>
  <shoutcast-mount>/channel8</shoutcast-mount>
  <shoutcast-mount>/channel9</shoutcast-mount>
</listen-socket>

Data File Area

Create an area for the media files and configuration.  For this example, it is assumed that these files are installed on a mounted disk in /disk/media

Create the following folders:
bin/
conf.dlna/
ezstream/bin
ezstream/cfg
ezstream/channel
Media/

EZStream Configuration Management

Create a configuration file for each stream you wish to have:

/disk/media/ezstream/cfg/N.cfg
<ezstream>
<url>http://localhost:8000/channelN</url>
<sourcepassword>PASS1234</sourcepassword>
<format>MP3</format>
<filename>/disk/media/ezstream/channel/N.m3u</filename>
<stream_once>0</stream_once>
<metadata_format>@s@</metadata_format>
<svrinfoname>Media Server</svrinfoname>
<svrinfourl>http://www.openserverproject.com</svrinfourl>
<svrinfogenre>Cantopop</svrinfogenre>
<svrinfodescription></svrinfodescription>
<svrinfobitrate>256</svrinfobitrate>
<svrinfochannels>2</svrinfochannels>
<svrinfosamplerate>44100</svrinfosamplerate>
<svrinfopublic>0</svrinfopublic>
</ezstream>

Create an m3u file in the channel folder for each stream.  Note that this is the file which you can update / change and then call update-ezstream.  Ensure the channel folder is writeable by the web server user.

/disk/media/ezstream/channel/N.m3u
/disk/media/Media/full/path/to/mp3/file1.mp3
/disk/media/Media/full/path/to/mp3/file2.mp3
Create a program to update the ezstream configuration based on configuration files in /disk/media/ezstream/cfg, and set its setuid/setgid bits such that other users can re-initialise the stream (most importantly, the web server user).

/disk/media/ezstream/bin/update-ezstream (.c)
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <linux/limits.h>
#include <libgen.h>
#include <signal.h>
#include <string.h>
int getprocesspid(char *procname, char *filter) ;
int main(int argc, char *argv[])
{
  int pid ;

  if (argc!=2 || argv[1][0]<'1' || argv[1][0]>'9') {
    printf("%s 1-9\n", argv[0]) ;
    exit(1) ;
  }

  // Find PID of running ezstream app
  char cfg[16] ;
  snprintf(cfg, sizeof(cfg), "/%c.xml", argv[1][0]) ;
  pid = getprocesspid("ezstream", cfg) ;
  // Change UID for ezstream user
  printf("Launched with uid: %d, ", getuid()) ;
  setreuid(geteuid(),geteuid()) ;
  printf("running with uid: %d\n", getuid()) ;
  // Send HUP signal, or launch server
  if (pid>0) {
    kill(pid, SIGHUP) ;
    return 0 ;
 
  } else {
 
    if (fork()==0) {
      char *thispath = dirname(argv[0]) ;
      char path[PATH_MAX+1] ;
      char *newargs[3] ;
   
      snprintf(path, sizeof(path), "%s/../cfg/%c.xml",
       thispath, argv[1][0]) ;
   
      newargs[0] = "/usr/local/bin/ezstream" ;
      newargs[1] = "-c" ;
      newargs[2] = path ;
      newargs[3] = NULL ;
   
      execv(newargs[0], newargs) ;
      printf("ERROR: Invalid program: %s %s %s\n",
          newargs[0], newargs[1], newargs[2]) ;
      return 1 ;
    }
    close(0) ;
    close(1) ;
    close(2) ;
    return 0 ;
  }
}
int getprocesspid(char *procname, char *filter)
{
  int pid=-1 ;
  char *args[5] ;
  args[0]="/bin/ps" ;
  args[1]="-fC" ;
  args[2]=procname ;
  args[3]=NULL ;
  int pipefd[2] ;
  pipe(pipefd) ;
  if (fork() == 0) {
    close(pipefd[0]) ;
    dup2(pipefd[1],1) ;
    close(pipefd[1]) ;
    char *args[5] ;
    args[0]="/bin/ps" ;
    args[1]="-fC" ;
    args[2]=procname ;
    args[3]=NULL ;
    execv(args[0], args) ;
    fprintf(stderr, "ERROR: Invalid program: %s %s %s\n",
          args[0], args[1], args[2]) ;
    exit(1) ;
  } else {
    char line[1024] ;
    int l=0 ;
    char ch ;
    int r ;
    close(pipefd[1]) ;
    do {
      if (r=read(pipefd[0], &ch, 1)) {
line[l++]=ch ;
line[l]='\0' ;
if (ch=='\n' || ch=='\r') {
  printf("line=%s\n", line) ;
  if (strstr(line, filter) != NULL) {
            sscanf(&line[9], "%d", &pid) ;
          }
          l=0 ;
}
      }
    } while (pid<0 && r==1 && l<sizeof(line)-1) ;
 
printf("\n pid=%d\n", pid) ;
    return pid ;
  }
}

Boot Configuration

Add a script to initialise the stream sources:

/disk/media/bin/init-stream-sources.sh
#!/bin/sh
/disk/media/ezstream/bin/update-ezstream 1
/disk/media/ezstream/bin/update-ezstream 2
/disk/media/ezstream/bin/update-ezstream 3
/disk/media/ezstream/bin/update-ezstream 4
/disk/media/ezstream/bin/update-ezstream 5
/disk/media/ezstream/bin/update-ezstream 6
/disk/media/ezstream/bin/update-ezstream 7
/disk/media/ezstream/bin/update-ezstream 8
/disk/media/ezstream/bin/update-ezstream 9
Make the following modifications to ensure the dlna media server and ezstream/shoutcast server starts up:

/etc/rc.local
/usr/local/sbin/minidlnad -f /disk/media/conf.dlna/minidlna.conf
/disk/media/bin/init-stream-sources.sh > /tmp/mediastreams.log 2>&1  






Saturday 21 September 2019

Ubuntu <-> Android <-> Draytek 2860VPN


On the Modem

Ensure PPTP VPN Service is Enabled in the Remote Access Control Setup.
Disable all other options.


In the PPTP General Setup, select MSCHAPv2 Only, and ensure the MPPE encryption is set to 128-bit.


In the Remote Dial In User area, create a new user, selecting PPTP only.  Create a username and password here.



On the Linux PC

Check your underlying (non VPN) connection, and ensure that the MTU is set to 1500:


Click on the network manager in the systray, and select "Edit Connections".  Add a New Point-to-point Tunneling Protocol (PPTP).


Suppy the IP address, or resolvable DNS name of the Draytek Modem, and then supply the username and password you set up on the modem in the previous section.

Finally, select Advanced, and ensure MPPE is selected and set to 128 bit.







Saturday 7 September 2019

Ubuntu 18.04 Hplip Scanner Problem

Problem

Printing works on Ubuntu 18.04 fine, but after a recent update, scanning on an HP MFP277 results in a SANE I/O Error 9.

Solution

Remove HPLIP:
$ sudo apt-get purge hplip
Download HP Public Key (Optional Step):
$ /usr/bin/gpg --keyserver pgp.mit.edu --recv-keys 0xA59047B9
Download HPLIP 19.x directly from HP, rather than from Ubuntu.
$ ./hplip-3.18.8.run
And select all the default responses.  Install plugins if requested:
$ hp-plugin
Checking for network connection...Downloading plug-in from: Plugin is not accessible. Trying to download it from fallback location: [https://developers.hp.com/sites/default/files/hplip-3.19.8-plugin.run]Receiving digital keys: /usr/bin/gpg --homedir /home/steve/.hplip/.gnupg --no-permission-warning --keyserver pgp.mit.edu --recv-keys 0x4ABA2F66DBD5A95894910E0673D770CDA59047B9
If the plugin is not accessible, as shown in the above example, simply download and execute the proposed plugin run file.
$ wget https://developers.hp.com/sites/default/files/hplip-3.19.8-plugin.run$ sh ./hplip-3.19.8-plugin.run
If the plugin install fails with the following error:
Plugin installation failederror: Python gobject/dbus may be not installederror: Plug-in install failed.
Ensure that a reboot following a previous upgrade is not pending.



Monday 12 August 2019

Google Actions, Firebase and async/await


Example Google Actions function which requests, waits, and returns data from a website.
Note that this requires billing to be activated if the website is not a google resource.

Note that the async/await and particularly the async in red

'use strict';
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const fetch = require("node-fetch");
//
// Web Fetch function
//
async function getData(url) {
   try {
        const res =
await fetch(url) ;
        const txt =
await res.text() ;
        console.log("TEXT: " + txt) ;
        return txt ;
   } catch(err) {
        console.log("ERR: " + err) ;
        throw err.replace(url, "website") ;
   }
}
 
//
// Exported Functions
//
 
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => { 
  const agent = new WebhookClient({ request, response });
      // My Function Handler
  async function myfunction(agent) {
    var url="https://url.to.fetch/" ;
   
await getData(url).then((txt) => {
       console.log("DATA: " + txt) ;
       process txt
       agent.add(...) ;
    }).catch((err) => {
      console.log("FAILED: " + err) ;
      agent.add("Error - " + err);
    }) ;
  }

  //
  // Setup
  //
  let intentMap = new Map();
  //intentMap.set('Default Welcome Intent', welcome);
  //intentMap.set('Default Fallback Intent', fallback);
  intentMap.set('forecast', forecast) ;
  agent.handleRequest(intentMap);
});



Saturday 9 February 2019

Philips Lightstrip Connections


Background

In order to connect hue lightstrips up in a flexible way, with easy to dismount connectors, and a simple way of making Y connections, I've connected a BT phone extension socket to the driver box.

This means that some soldering is necessary, but once completed, it is possible to use phone extension cables and splitters.



Ingredients

  • Philips Lightstrip+ 2m (Including controller unit)
  • BT Extension Cable (6 Wire)
  • Plug Adaptor
  • Socket Adaptor
  • Mouldable Polymorphic Plastic
  • White Heat Shrink Sleeving (~1.5mm and ~14mm)

Method

Controller

  1. Cut the socket part off the extension cable, leaving a length of at least 300mm
  2. Open the controller unit box, and de-solder the 6 wires connected to the C,R,G,B,W,VCC terminals.
  3. Using the BT socket / cable, strip the wire associated with pin 1 - if in doubt, connect the plug into the socket, and buzz out the connections.
  4. Use some fine heatshrink cable on the wire, which will protect it from melting when soldering.
  5. Solder the wire to the controller board (VCC)
  6. Repeat for the other 5 wires.

Cable to Lightstrip
  1. Cut the remaining part of the extension cable (with the plug) to the desired length
  2. Strip the wire associated with pin 1
  3. Use some fine heatshrink cable on the wire, which will protect it from melting when soldering.
  4. Solder the wire to a plug-in adaptor, or directly to a length of lightstrip.
  5. Repeat for the other 5 wires

Testing

  1. Connect the BT socket and plug together, and buzz through VCC on the lightstrip to pin 1 on the controller, and make sure they are connected
  2. Buzz pin 1 to pin 2, and make sure they are not connected
  3. Repeat for the other 5 pins

Closing Up

  1. Put the lid back on the controller, making sure that the new wire is adequately supported
  2. Using some polymorphic plastic, craft a connector body over the plug adaptor or the end of the lightstrip
  3. Slide a short length of white heatshrink sleeving over the new connector body, and shrink

You can now use BT splitter sockets and extension cables for your Philips Hue light strips.

Notes

Ensure 6-wire BT cables and splitters are used.  4-wire ones will be useless.
Philips Hue Lighstrip Plus uses 24V and has 6 connections.  
Some other lighstrips (including the older Philips Hue ones) use 12V, and 4 or 5 connecitons.
Don't get them muddled up.




Monday 4 February 2019

Home Automation with Google Home Routines

The Google Home is a great concept, and if you want to do something simple, it is great.  If you want to be a little more clever, however, there are several gotchas.

Setup

Broadlink Mini 3 IR Sender

tv - Television Device (Panasonic TV, from the library)
hifi - Custom Device (Denon Hifi, Manually configured)
tv on - Scene to turn on TV using a Discrete ON sequence (learned from a raspberry Pi, rather than the remote, which doesn't have discrete on/off codes), turns on the hifi, mutes the TV, and switches the hifi to use the TV output.
tv off - Scene to turn off the TV and Hifi using Discrete OFF sequences

Philips Hue

5 Light bulbs around the house
tv lights - Scene to set the lights in the living room for TV watching

Google Home

Routine: "tv on, turn on the tv, turn the tv on"
Activate Scenes: "tv on", "tv lights"
Say: "OK, Television is On"

Actions and Responses

1. OK Google, TV On
This turns on the TV, Hifi, and routes the audio as needed, and says "OK, Television is On"

2. OK Google, Turn the TV On
This turns the TV on, but just the TV

3. OK Google, Turn the TV On
This turns the TV off

4. OK Google, Turn on the TV
This responds with "OK, Executing 3 scenes", and promptly executes "tv on", "tv off" and "tv lights"

Analysis

The Google Home is trying to be clever, and looks for devices or sequences which have the matching device type, or contain the name.

1: works because the keyword "turn on", or "activate" etc. is not used.
2: finds a device of type 'TV' (the name in this case is irrelevant), and sends the programmed 'on/off' sequence.
3: As 2, but because the TV was already on, and the device has an 'on/off' control button on the remote, actually turns the device off, rather than on.
4: This searches for matching scenes, rather than devices, and finds 3 scenes with the name TV in them.

Changes Stage 1

First thing to change is to remove the tv device from the Broadlink Mini, and re-install it as a custom device, so that the underlying system does not know that it is a TV.  Also, give it a different name.

Broadlink Mini 3 IR Sender

pana - Custom Device (Panasonic TV, Manually configured)
hifi - Custom Device (Denon Hifi, Manually configured)
tv on - Scene to turn on TV using a Discrete ON sequence (learned from a raspberry Pi, rather than the remote, which doesn't have discrete on/off codes), turns on the hifi, mutes the TV, and switches the hifi to use the TV output.
tv off - Scene to turn off the TV and Hifi using Discrete OFF sequences

Philips Hue

5 Light bulbs around the house
tv lights - Scene to set the lights in the living room for TV watching

Google Home

Routine: "tv on, turn on the tv, turn the tv on"
Activate Scenes: "tv on", "tv lights"
Say: "OK, Television is On"

Changes Stage 1, Actions and Responses

5. OK Google, Turn on the Television
This turns on the TV, Hifi, and routes the audio as needed, and says "OK, Television is On"

Analysis Stage 1

5: This now turns on the TV as expected, because there is no longer a device of type 'TV' and there are no scenes containing the name "television".

Changes Stage 2

The next set of changes is to remove the name 'tv' from any device name or sequence.

Broadlink Mini 3 IR Sender

p99 - Custom Device (Panasonic TV, Manually configured)
d99 - Custom Device (Denon Hifi, Manually configured)
p99on - Scene to turn on TV using a Discrete ON sequence (learned from a raspberry Pi, rather than the remote, which doesn't have discrete on/off codes), turns on the hifi, mutes the TV, and switches the hifi to use the TV output.
p99off - Scene to turn off the TV and Hifi using Discrete OFF sequences

Philips Hue

5 Light bulbs around the house
h99lights - Scene to set the lights in the living room for TV watching

Google Home

Routine: "tv on, television on, turn on the tv, turn the tv on"
Activate Scenes: "p99on", "h99lights"
Say: "OK, Television is On"

Stage 2, Actions and Responses

6. Say "OK Google, TV On"
6. Say "OK Google, Television On"
6. Say "OK Google, Turn on the TV"
6. Say "OK Google, Turn the TV On"
This turns on the TV, Hifi, and routes the audio as needed, and says "OK, Television is On"

Stage 2, Analysis

6: This now works, because there are no matching devices, names or scenes.

Conclusion

The google home has a pecking order in which it processes requests, and it looks like:

1. Is there a matching device, and if so, does it have the required controls needed (e.g. on/off)
2. Are there any matching scenes
3. Is there a matching routine

For the first option, any inadequacies in the device itself (e.g. toggling power, rather than discrete on/off) show themselves.  This also means that other activities within the routine cannot be executed (e.g. a routine which would both turn on a hifi, set the volume and input to a chromecast audio, and stream a specific radio channel).

For the second step, if the exact scene is not named, all matching scenes are executed. It is possible to turn off the TV by saying "OK Google, turn on tv off" if there is a scene called "tv off", but it isn't very intuitive.

The last step is the most flexible, but it is essential that the possibility of matches at previous steps is eliminated.

Recommendations

1. Don't use a specific device type where possible (e.g. don't select a TV device, select a generic one)
2. Don't use names of the devices for the devices or any scenes associated with the device
3. Add all possible commands to the routines

Request from Google that routines can be set to a higher priority in the pecking order.




Sunday 27 January 2019

Discrete IR Codes for Panasonic Viera and Denon RC-DM41DAB Hifi

These are lircd.conf files for infrared codes which are supported by the device, but not possible to produce with the remote control.

Panasonic Viera TX50CX

begin remote

  name panasonic

  bits            24
  flags           SPACE_ENC
  eps             30
  aeps            100

  header          3455  1736

  one             433   1305
  zero            433   436
  ptrail          433
  pre_data_bits   24
  pre_data        0x400401
  gap             74568
  toggle_bit_mask 0x0
  frequency       38000
    begin codes
          EXT_ON                   0x007C7D
          EXT_OFF                  0x00FCFD
          EXT_AV1                  0x008081
          EXT_AV2                  0x004041
          EXT_HDMI1                0x200D2C
          EXT_HDMI2                0x208DAC
          EXT_HDMI3                0x204D6C
          EXT_UHF                  0x40EEAF
          EXT_DVB                  0x401E5F
          EXT_FREESAT              0x409EDF
          EXT_OTHERSAT             0x405E1F

          EXT_MEDIA                0x90D544
    end codes
end remote

Denon RC-DM41DAB


begin remote
  name            RC1214
  bits            24
  flags           SPACE_ENC
  eps             30
  aeps            100

  header          3479  1712

  one             420   1261
  zero            420   425
  ptrail          420
  pre_data_bits   24
  pre_data        0x2A4C0A
  gap             50587
  toggle_bit_mask 0x0
  frequency       38000
    begin codes
          EXT_ON                   0x880280
          EXT_OFF                  0x84028C
          EXT_DAB                  0x65026D
          EXT_FM                   0x690261
          EXT_AM                   0x610269
          EXT_CDPLAY               0xC102C9
          EXT_PAUSE                0x890281
          EXT_DISC                 0x89C241
          EXT_FOLDER               0x81C249
    end codes
end remote

Format of the Commands

The commands are in the format:

       16 Bits          8 Bits              16 Bits           8 Bits
+-------------------+----------------+----------------------+-----------+
| Manufacturer Code | Device         |    Function Code     | Check sum |
+-------------------+----------------+----------------------+-----------+
 lsb                 lsb              lsb                    lsb

The Checksum is a simple Xor of the Device and Function Code Bytes

The msb/lsb are the opposite way around to 'normal' so the codes must be modified (flipped) for the lirc configuration files.


Panasonic Viera Worked Example

The Device code for Panasonic is an 8-bit number.
The Function Code is made up of an 8-bit sub device and an 8-bit original button code

       16 Bits          8 Bits          8 Bits     8 Bits     8 Bits
+-------------------+----------------+----------+-----------+-----------+
| Manufacturer Code | Device         | Sub Dev  |    OBC    | Check sum |
+-------------------+----------------+----------+-----------+-----------+

The Manufacturer code for the panasonic TV is 144, and the device ID is 128

    0x2002 -> 0010 0000 0000 0010
                      <--> 
              0100 0000 0000 0100 -> 0x4004

    0x80   ->  1000 0000
                 <-->
               0000 0001  -> 0x01

So the Pre-Data in the lirc configuration file is 0x400401


The 'Extended On' command command for device 128 is subdevice 0, OBC 62

    0x00   ->  0000 0000
                 <-->
               0000 0000  -> 0x00

    0x3E   ->  0011 1110
    62(dec)      <-->
               0111 1100  -> 0x7C   

So the Function Code for this command ix 0x007C

The Checksum is 0x01 xor 0x00 xor 0x7C -> 0x7D

So the code for 'Extended On' in the lirc configuration file is 0x007C7D




Denon RC1214 Worked Example

The Device Code in Denon Terminology is made of a nybble of zeroes, and a 4-bit Genre 1
The Function Code in Denon Terminology is made of a 4-bit Genre 2 and a 12-bit Data code

       16 Bits                4 Bits    4 Bits     12 Bits       8 Bits
+-------------------+------+----------+--------+-------------+-----------+
| Manufacturer Code | 0000 |  Genre1  | Genre2 |    Data     | Check sum |
+-------------------+------+----------+--------+-------------+-----------+

The Manufacturer Code for the RC1214 remote is: 0x3254, and all commands have a Genre1 of 5, but the numbers are stored lsb first, so they need flipping around:

    0x3254 -> 0011 0010 0101 0100
                      <--> 
              0010 1010 0100 1100 -> 0x2A4C

    0x5   ->  0101
              <-->
              1010  -> 0xA

So the Pre-Data in the lirc configuration file is 0x2A4C0A

The Genre2 code and data codes for the Extended 'On' command are 0x01 and 0x401 respectively, but need msb/lsb flipping:

    0x1  -> 0001
            <--> 
            1000 -> 0x8

    0x401-> 0100 0000 0001
                 <-->
            1000 0000 0010 -> 0x802

So the Function Code for this command is 0x8802


The Checksum is 0x0A xor 0x88 xor 0x02 -> 0x80

So the code for 'Extended On' in the lirc configuration file is 0x880280