tag:blogger.com,1999:blog-10820716359982773712024-03-05T05:19:52.008-08:00dephioxdephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.comBlogger24125tag:blogger.com,1999:blog-1082071635998277371.post-20165757869968909132020-02-13T18:27:00.001-08:002022-11-17T23:33:12.502-08:00The amazing update process of windows 10<script src="https://cdn.jsdelivr.net/gh/google/code-prettify@master/loader/run_prettify.js"></script><b>Changing windows 10 active hours. Or How to *disable* automatic reboots in Windows 10?</b><br /><br />
<h4><span style="font-size: xx-small;">EDIT: "Active hours" does not always work. On the 16th of November 2022 I had the "Windows needs update" icon in my taskbar. After some hours the screen flickered and the colour of some letters became distorted, red/blue. It was a NVIDIA update and it changed the screen update frequency without any approval.</span></h4><h4><span style="font-size: xx-small;">Warning: This may or may not work on your windows version. It works on 1909 pro. Test the "Set-ItemProperty" lines below in an powershell before trying to install the service. </span></h4>
<span style="color: red;"><span style="background-color: white; font-size: x-small;">EDIT: Someone tried this and received a message that security policies denied the execution of the script. Have a look at <b>Get-ExecutionPolicy -List</b> before you start. You are on your own here, but</span><b style="font-size: small;"> </b><b><span style="font-size: x-small;">Set-ExecutionPolicy -ExecutionPolicy Unrestricted</span></b><span style="background-color: white; font-size: x-small;"> will remove the message. You can turn it back on again after the script has been installed with <b>Set-ExecutionPolicy -ExecutionPolicy Undefined</b>.</span></span><br />
<br />
<br />
I guess some already knows that there exists an amazing system in windows 10 for fetching updates.<br />
<br />
If you assign some useless, power consuming process to your PC during your sleep hours, windows 10 will/will not stop this process and restart your computer, effectively putting it into a high-low power state where it will await you when you meet your pc in the morning.<br />
<br />
If you are already experiencing BSOD events with your pc this may also serve as an indicator for your hearth health. Is the log-in screen and lost data due to a BSOD or is it the superior windows overlords updating some feature? A feature that could increase your BSOD problems? Can you still raise your left arm?<br />
<br />
But the downside of this feature is that you can't always leave it on, it can be off for eighteen hours a day, then there will be a six hour delay in witch the computer will not/will restart randomly.<br />
<br />
In my quest to battle this gap I searched the internet. I found several tools that try to circumvent the six hour gap. There are tools out there that will help you, "Windows 10 Reboot Blocker" is such an alternative, and from user reports it seems to work OK.<br />
<br />
The problem with this, of course, is that you have to trust the writer of this software with your PC. Typically there are no source code with these things. Who knows, are you introducing some dormant maleware into your PC? E.g. <a href="https://www.dailymail.co.uk/news/article-7992175/CIA-secretly-OWNED-encrypted-code-making-machines-decades-allowing-spy-governments.html" target="_blank">CIA scored intelligence 'coup of the century'</a><br />
<br />
I do not believe that the Reboot Blocker is such a tool, but every undocumented tool installed onto the PC increases the risk.<br />
<br />
The simplest solution would be if the hardly working Microsoft employees would disable the six hour gap. But for me, knowing that those people will never do that, the answer came from an interesting blog post at <a href="https://docs.microsoft.com/en-us/archive/msdn-magazine/2016/may/windows-powershell-writing-windows-services-in-powershell" target="_blank">Windows PowerShell - Writing Windows Services in PowerShell</a>.<br />
<br />
<br />
He shares a wonderful script that you can read through yourself, letting you run a system service in windows. Here is his script, <a href="https://github.com/JFLarvoire/SysToolsLib/blob/master/PowerShell/PSService.ps1" target="_blank">PSService.ps1</a>.<br />
<div>
<br /></div>
<div>
Combine this script with the knowledge that if you enter something like the text below in a powershell it will change the "active hours" of your computer:</div>
<div>
<br /></div>
<div>
<pre class="prettyprint"><blockquote class="tr_bq">
$mystart = 1
$mystop = 16
Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings -Name ActiveHoursStart -Value $mystart
Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings -Name ActiveHoursEnd -Value $mystop
</blockquote>
</pre>
</div>
<div>
<br /></div>
<div>
<div>
Make $mystart and $mystop roll in front of you like an artillery barrage and you have removed the six hour gap.</div>
<div>
<br /></div>
<div>
Since the script name already served my needs, starting with an "A", I did not change the name of it. And the script is well commented, it will be easy to change the name to something less appropriate.</div>
</div>
<div>
<br />
What I did was adding one additional timer that repeats once after ten seconds. And I changed the original timer to 3600 seconds. Both timers trigger the same event. The code now gets the current hour (0-23) and calls Set-ItemProperty on the register values that determines the active hours for the PC. It sets the start of active hours to one hour before the current time and the end time to fifteen hours after the current time.<br />
<br /></div>
<div>
<div>
Download the script from github. Link above. Read it.</div>
<div>
Edit it like this:</div>
</div>
<div>
<br /></div>
<div>
Around line 1038:
<br />
<pre class="prettyprint"><blockquote class="tr_bq">
###### Example that wakes up and logs a line every 10 sec: ######
# Start a one shot timer
$timerName = "Initial adjust time"
$period = 10 # seconds
$mytimer = new-object System.Timers.Timer
$mytimer.Interval = ($period * 1000) # Milliseconds
$mytimer.AutoReset = $false # Make it fire once
Register-ObjectEvent $mytimer -EventName Elapsed -SourceIdentifier $timerName -MessageData "TimerTick"
$mytimer.start() #
# Start a periodic timer
</blockquote>
</pre>
</div>
And around line 1086 (after you inserted the text above)<br />
<br />
<pre class="prettyprint"><blockquote class="tr_bq">
"TimerTick" { # Example. Periodic event generated for this example
$myhour = Get-Date -UFormat "%H"
$mystart = ([int]$myhour) - 1
if (([int]$mystart) -lt 0)
{
$mystart = ([int]$mystart) + 24
}
$mystop = ([int]$myhour) + 15
if (([int]$mystop) -gt 23)
{
$mystop = ([int]$mystop) - 24
}
Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings -Name ActiveHoursStart -Value $mystart
Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings -Name ActiveHoursEnd -Value $mystop
Log "$scriptName -Service # Changed activation hours to $mystart -> $mystop"
}
default { # Should not happen
</blockquote>
</pre>
<br />
<div>
<br /></div>
<div>
Open a powershell with administrative rights and go to the folder where you placed and edited the PSService.ps1</div>
<div>
<br /></div>
<div>
<div>
type these lines:</div>
<blockquote class="tr_bq">
.\PSService.ps1 -Setup<br />
.\PSService.ps1 -Start<br />
type C:\Windows\Logs\PSService.log</blockquote>
<div>
<br /></div>
<div>
You should see some output.</div>
<div>
For me I saw this:</div>
<pre class="prettyprint">2020-02-14 04:54:52 11516 dephiox\dephiox .\PSService.ps1 -Setup
2020-02-14 04:54:52 11516 dephiox\dephiox PSService.ps1 -Setup # Configuring the service to run by default as LocalSystem
2020-02-14 04:54:54 11516 dephiox\dephiox .\PSService.ps1 -Start
2020-02-14 04:54:54 4784 NT AUTHORITY\SYSTEM & 'C:\Windows\System32\PSService.ps1' -SCMStart
2020-02-14 04:54:54 4784 NT AUTHORITY\SYSTEM PSService.ps1 -SCMStart: Starting script 'C:\Windows\System32\PSService.ps1' -Service
2020-02-14 04:54:55 1260 NT AUTHORITY\SYSTEM & 'C:\Windows\System32\PSService.ps1' -Service
2020-02-14 04:55:05 1260 NT AUTHORITY\SYSTEM PSService.ps1 -Service # Changed activation hours to 3 -> 19
</pre>
</div>
<div>
The "services" app looks like this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOgAZb-QZLs1vkSqd9BkvXm6k34-CDI2f9BtfOVmSHbDfmbFBrHBlFR-5dLAXpXVefUZfw4lssAf623I2HgUxw0Up7XbJ1jQfQYHhcj_x-uLJvN7VeFPVbrwgDfxUPACIHMdZsjTL7KVE/s1600/powershellscript.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="437" data-original-width="1600" height="174" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOgAZb-QZLs1vkSqd9BkvXm6k34-CDI2f9BtfOVmSHbDfmbFBrHBlFR-5dLAXpXVefUZfw4lssAf623I2HgUxw0Up7XbJ1jQfQYHhcj_x-uLJvN7VeFPVbrwgDfxUPACIHMdZsjTL7KVE/s640/powershellscript.PNG" width="640" /></a></div>
<br /></div>
<div>
Have a look at your current activation hours.</div>
<div>
<br /></div>
<div>
Follow the progress through the day by repeating</div>
<blockquote class="tr_bq">
type C:\Windows\Logs\PSService.log</blockquote>
<div>
<br /></div>
<div>
After a while you should see something like:</div>
<div>
<br /></div>
<div>
<pre class="prettyprint"><span style="font-size: x-small;">
2020-02-14 07:44:38 5180 NT AUTHORITY\SYSTEM PSService.ps1 -Service # Changed activation hours to 6 -> 22
2020-02-14 08:44:28 5180 NT AUTHORITY\SYSTEM PSService.ps1 -Service # Changed activation hours to 7 -> 23
2020-02-14 09:44:28 5180 NT AUTHORITY\SYSTEM PSService.ps1 -Service # Changed activation hours to 8 -> 0
2020-02-14 10:44:28 5180 NT AUTHORITY\SYSTEM PSService.ps1 -Service # Changed activation hours to 9 -> 1
2020-02-14 11:44:28 5180 NT AUTHORITY\SYSTEM PSService.ps1 -Service # Changed activation hours to 10 -> 2
2020-02-14 12:44:28 5180 NT AUTHORITY\SYSTEM PSService.ps1 -Service # Changed activation hours to 11 -> 3
</span></pre>
<br /></div>
<div>
(For you it should show the hour(in 24 hour), the current hour -1 and the current hour plus fifteen hours.</div>
<div>
<br /></div>
<div>
If you check your activation hours in the settings you should see that the times change. Wait another hour and confirm your active hours are rolling in front of you.</div>
<div>
<br /></div>
<div>
You have now escaped the six hour gap in windows updates. You must now install the updates yourself, at the time you choose.<br />
<br />
<br />
If you want to remove the script type:<br />
<blockquote class="tr_bq">
.\PSService.ps1 -Stop</blockquote>
into the powershell window. And open a command prompt with admin rights and type:<br />
<blockquote class="tr_bq">
C:\Windows\system32>sc delete PSService</blockquote>
And it will respond with:<br />
<blockquote class="tr_bq">
[SC] DeleteService SUCCESS</blockquote>
<br />
<br />
Here is jf.larvoire's powershell script with my additions:</div>
<pre class="prettyprint"><blockquote class="tr_bq">
###############################################################################
# #
# File name PSService.ps1 #
# #
# Description A sample service in a standalone PowerShell script #
# #
# Notes The latest PSService.ps1 version is available in GitHub #
# repository https://github.com/JFLarvoire/SysToolsLib/ , #
# in the PowerShell subdirectory. #
# Please report any problem in the Issues tab in that #
# GitHub repository in #
# https://github.com/JFLarvoire/SysToolsLib/issues #
# If you do submit a pull request, please add a comment at #
# the end of this header with the date, your initials, and #
# a description of the changes. Also update $scriptVersion. #
# #
# The initial version of this script was described in an #
# article published in the May 2016 issue of MSDN Magazine. #
# https://msdn.microsoft.com/en-us/magazine/mt703436.aspx #
# This updated version has one major change: #
# The -Service handler in the end has been rewritten to be #
# event-driven, with a second thread waiting for control #
# messages coming in via a named pipe. #
# This allows fixing a bug of the original version, that #
# did not stop properly, and left a zombie process behind. #
# The drawback is that the new code is significantly longer,#
# due to the added PowerShell thread management routines. #
# On the other hand, these thread management routines are #
# reusable, and will allow building much more powerful #
# services. #
# #
# Dynamically generates a small PSService.exe wrapper #
# application, that in turn invokes this PowerShell script. #
# #
# Some arguments are inspired by Linux' service management #
# arguments: -Start, -Stop, -Restart, -Status #
# Others are more in the Windows' style: -Setup, -Remove #
# #
# The actual start and stop operations are done when #
# running as SYSTEM, under the control of the SCM (Service #
# Control Manager). #
# #
# To create your own service, make a copy of this file and #
# rename it. The file base name becomes the service name. #
# Then implement your own service code in the if ($Service) #
# {block} at the very end of this file. See the TO DO #
# comment there. #
# There are global settings below the script param() block. #
# They can easily be changed, but the defaults should be #
# suitable for most projects. #
# #
# Service installation and usage: See the dynamic help #
# section below, or run: help .\PSService.ps1 -Detailed #
# #
# Debugging: The Log function writes messages into a file #
# called C:\Windows\Logs\PSService.log (or actually #
# ${env:windir}\Logs\$serviceName.log). #
# It is very convenient to monitor what's written into that #
# file with a WIN32 port of the Unix tail program. Usage: #
# tail -f C:\Windows\Logs\PSService.log #
# #
# History #
# 2015-07-10 JFL jf larvoire hpe.com created this script. #
# 2015-10-13 JFL Made this script completely generic, and added comments #
# in the header above. #
# 2016-01-02 JFL Moved the Event Log name into new variable $logName. #
# Improved comments. #
# 2016-01-05 JFL Fixed the StartPending state reporting. #
# 2016-03-17 JFL Removed aliases. Added missing explicit argument names. #
# 2016-04-16 JFL Moved the official repository on GitHub. #
# 2016-04-21 JFL Minor bug fix: New-EventLog did not use variable $logName.#
# 2016-05-25 JFL Bug fix: The service task was not properly stopped; Its #
# finally block was not executed, and a zombie task often #
# remained. Fixed by using a named pipe to send messages #
# to the service task. #
# 2016-06-05 JFL Finalized the event-driven service handler. #
# Fixed the default command setting in PowerShell v2. #
# Added a sample -Control option using the new pipe. #
# 2016-06-08 JFL Rewrote the pipe handler using PSThreads instead of Jobs. #
# 2016-06-09 JFL Finalized the PSThread management routines error handling.#
# This finally fixes issue #1. #
# 2016-08-22 JFL Fixed issue #3 creating the log and install directories. #
# Thanks Nischl. #
# 2016-09-06 JFL Fixed issue #4 detecting the System account. Now done in #
# a language-independent way. Thanks A Gonzalez. #
# 2016-09-19 JFL Fixed issue #5 starting services that begin with a number.#
# Added a $ServiceDescription string global setting, and #
# use it for the service registration. #
# Added comments about Windows event logs limitations. #
# 2016-11-17 RBM Fixed issue #6 Mangled hyphen in final Unregister-Event. #
# 2017-05-10 CJG Added execution policy bypass flag. #
# 2017-10-04 RBL rblindberg Updated C# code OnStop() routine fixing #
# orphaned process left after stoping the service. #
# 2017-12-05 NWK omrsafetyo Added ServiceUser and ServicePassword to the #
# script parameters. #
# 2017-12-10 JFL Removed the unreliable service account detection tests, #
# and instead use dedicated -SCMStart and -SCMStop #
# arguments in the PSService.exe helper app. #
# Renamed variable userName as currentUserName. #
# Renamed arguments ServiceUser and ServicePassword to the #
# more standard UserName and Password. #
# Also added the standard argument -Credential. #
# #
###############################################################################
#Requires -version 2
<#
.SYNOPSIS
A sample Windows service, in a standalone PowerShell script.
.DESCRIPTION
This script demonstrates how to write a Windows service in pure PowerShell.
It dynamically generates a small PSService.exe wrapper, that in turn
invokes this PowerShell script again for its start and stop events.
.PARAMETER Start
Start the service.
.PARAMETER Stop
Stop the service.
.PARAMETER Restart
Stop then restart the service.
.PARAMETER Status
Get the current service status: Not installed / Stopped / Running
.PARAMETER Setup
Install the service.
Optionally use the -Credential or -UserName arguments to specify the user
account for running the service. By default, uses the LocalSystem account.
Known limitation with the old PowerShell v2: It is necessary to use -Credential
or -UserName. For example, use -UserName LocalSystem to emulate the v3+ default.
.PARAMETER Credential
User and password credential to use for running the service.
For use with the -Setup command.
Generate a PSCredential variable with the Get-Credential command.
.PARAMETER UserName
User account to use for running the service.
For use with the -Setup command, in the absence of a Credential variable.
The user must have the "Log on as a service" right. To give him that right,
open the Local Security Policy management console, go to the
"\Security Settings\Local Policies\User Rights Assignments" folder, and edit
the "Log on as a service" policy there.
Services should always run using a user account which has the least amount
of privileges necessary to do its job.
Three accounts are special, and do not require a password:
* LocalSystem - The default if no user is specified. Highly privileged.
* LocalService - Very few privileges, lowest security risk.
Apparently not enough privileges for running PowerShell. Do not use.
* NetworkService - Idem, plus network access. Same problems as LocalService.
.PARAMETER Password
Password for UserName. If not specified, you will be prompted for it.
It is strongly recommended NOT to use that argument, as that password is
visible on the console, and in the task manager list.
Instead, use the -UserName argument alone, and wait for the prompt;
or, even better, use the -Credential argument.
.PARAMETER Remove
Uninstall the service.
.PARAMETER Service
Run the service in the background. Used internally by the script.
Do not use, except for test purposes.
.PARAMETER SCMStart
Process Service Control Manager start requests. Used internally by the script.
Do not use, except for test purposes.
.PARAMETER SCMStop
Process Service Control Manager stop requests. Used internally by the script.
Do not use, except for test purposes.
.PARAMETER Control
Send a control message to the service thread.
.PARAMETER Version
Display this script version and exit.
.EXAMPLE
# Setup the service and run it for the first time
C:\PS>.\PSService.ps1 -Status
Not installed
C:\PS>.\PSService.ps1 -Setup
C:\PS># At this stage, a copy of PSService.ps1 is present in the path
C:\PS>PSService -Status
Stopped
C:\PS>PSService -Start
C:\PS>PSService -Status
Running
C:\PS># Load the log file in Notepad.exe for review
C:\PS>notepad ${ENV:windir}\Logs\PSService.log
.EXAMPLE
# Stop the service and uninstall it.
C:\PS>PSService -Stop
C:\PS>PSService -Status
Stopped
C:\PS>PSService -Remove
C:\PS># At this stage, no copy of PSService.ps1 is present in the path anymore
C:\PS>.\PSService.ps1 -Status
Not installed
.EXAMPLE
# Configure the service to run as a different user
C:\PS>$cred = Get-Credential -UserName LAB\Assistant
C:\PS>.\PSService -Setup -Credential $cred
.EXAMPLE
# Send a control message to the service, and verify that it received it.
C:\PS>PSService -Control Hello
C:\PS>Notepad C:\Windows\Logs\PSService.log
# The last lines should contain a trace of the reception of this Hello message
#>
[CmdletBinding(DefaultParameterSetName='Status')]
Param(
[Parameter(ParameterSetName='Start', Mandatory=$true)]
[Switch]$Start, # Start the service
[Parameter(ParameterSetName='Stop', Mandatory=$true)]
[Switch]$Stop, # Stop the service
[Parameter(ParameterSetName='Restart', Mandatory=$true)]
[Switch]$Restart, # Restart the service
[Parameter(ParameterSetName='Status', Mandatory=$false)]
[Switch]$Status = $($PSCmdlet.ParameterSetName -eq 'Status'), # Get the current service status
[Parameter(ParameterSetName='Setup', Mandatory=$true)]
[Parameter(ParameterSetName='Setup2', Mandatory=$true)]
[Switch]$Setup, # Install the service
[Parameter(ParameterSetName='Setup', Mandatory=$true)]
[String]$UserName, # Set the service to run as this user
[Parameter(ParameterSetName='Setup', Mandatory=$false)]
[String]$Password, # Use this password for the user
[Parameter(ParameterSetName='Setup2', Mandatory=$false)]
[System.Management.Automation.PSCredential]$Credential, # Service account credential
[Parameter(ParameterSetName='Remove', Mandatory=$true)]
[Switch]$Remove, # Uninstall the service
[Parameter(ParameterSetName='Service', Mandatory=$true)]
[Switch]$Service, # Run the service (Internal use only)
[Parameter(ParameterSetName='SCMStart', Mandatory=$true)]
[Switch]$SCMStart, # Process SCM Start requests (Internal use only)
[Parameter(ParameterSetName='SCMStop', Mandatory=$true)]
[Switch]$SCMStop, # Process SCM Stop requests (Internal use only)
[Parameter(ParameterSetName='Control', Mandatory=$true)]
[String]$Control = $null, # Control message to send to the service
[Parameter(ParameterSetName='Version', Mandatory=$true)]
[Switch]$Version # Get this script version
)
$scriptVersion = "2017-12-10"
# This script name, with various levels of details
$argv0 = Get-Item $MyInvocation.MyCommand.Definition
$script = $argv0.basename # Ex: PSService
$scriptName = $argv0.name # Ex: PSService.ps1
$scriptFullName = $argv0.fullname # Ex: C:\Temp\PSService.ps1
# Global settings
$serviceName = $script # A one-word name used for net start commands
$serviceDisplayName = "A Sample PowerShell Service"
$ServiceDescription = "Shows how a service can be written in PowerShell"
$pipeName = "Service_$serviceName" # Named pipe name. Used for sending messages to the service task
# $installDir = "${ENV:ProgramFiles}\$serviceName" # Where to install the service files
$installDir = "${ENV:windir}\System32" # Where to install the service files
$scriptCopy = "$installDir\$scriptName"
$exeName = "$serviceName.exe"
$exeFullName = "$installDir\$exeName"
$logDir = "${ENV:windir}\Logs" # Where to log the service messages
$logFile = "$logDir\$serviceName.log"
$logName = "Application" # Event Log name (Unrelated to the logFile!)
# Note: The current implementation only supports "classic" (ie. XP-compatble) event logs.
# To support new style (Vista and later) "Applications and Services Logs" folder trees, it would
# be necessary to use the new *WinEvent commands instead of the XP-compatible *EventLog commands.
# Gotcha: If you change $logName to "NEWLOGNAME", make sure that the registry key below does not exist:
# HKLM\System\CurrentControlSet\services\eventlog\Application\NEWLOGNAME
# Else, New-EventLog will fail, saying the log NEWLOGNAME is already registered as a source,
# even though "Get-WinEvent -ListLog NEWLOGNAME" says this log does not exist!
# If the -Version switch is specified, display the script version and exit.
if ($Version) {
Write-Output $scriptVersion
return
}
#-----------------------------------------------------------------------------#
# #
# Function Now #
# #
# Description Get a string with the current time. #
# #
# Notes The output string is in the ISO 8601 format, except for #
# a space instead of a T between the date and time, to #
# improve the readability. #
# #
# History #
# 2015-06-11 JFL Created this routine. #
# #
#-----------------------------------------------------------------------------#
Function Now {
Param (
[Switch]$ms, # Append milliseconds
[Switch]$ns # Append nanoseconds
)
$Date = Get-Date
$now = ""
$now += "{0:0000}-{1:00}-{2:00} " -f $Date.Year, $Date.Month, $Date.Day
$now += "{0:00}:{1:00}:{2:00}" -f $Date.Hour, $Date.Minute, $Date.Second
$nsSuffix = ""
if ($ns) {
if ("$($Date.TimeOfDay)" -match "\.\d\d\d\d\d\d") {
$now += $matches[0]
$ms = $false
} else {
$ms = $true
$nsSuffix = "000"
}
}
if ($ms) {
$now += ".{0:000}$nsSuffix" -f $Date.MilliSecond
}
return $now
}
#-----------------------------------------------------------------------------#
# #
# Function Log #
# #
# Description Log a string into the PSService.log file #
# #
# Arguments A string #
# #
# Notes Prefixes the string with a timestamp and the user name. #
# (Except if the string is empty: Then output a blank line.)#
# #
# History #
# 2016-06-05 JFL Also prepend the Process ID. #
# 2016-06-08 JFL Allow outputing blank lines. #
# #
#-----------------------------------------------------------------------------#
Function Log () {
Param(
[Parameter(Mandatory=$false, ValueFromPipeline=$true, Position=0)]
[String]$string
)
if (!(Test-Path $logDir)) {
New-Item -ItemType directory -Path $logDir | Out-Null
}
if ($String.length) {
$string = "$(Now) $pid $currentUserName $string"
}
$string | Out-File -Encoding ASCII -Append "$logFile"
}
#-----------------------------------------------------------------------------#
# #
# Function Start-PSThread #
# #
# Description Start a new PowerShell thread #
# #
# Arguments See the Param() block #
# #
# Notes Returns a thread description object. #
# The completion can be tested in $_.Handle.IsCompleted #
# Alternative: Use a thread completion event. #
# #
# References #
# https://learn-powershell.net/tag/runspace/ #
# https://learn-powershell.net/2013/04/19/sharing-variables-and-live-objects-between-powershell-runspaces/
# http://www.codeproject.com/Tips/895840/Multi-Threaded-PowerShell-Cookbook
# #
# History #
# 2016-06-08 JFL Created this function #
# #
#-----------------------------------------------------------------------------#
$PSThreadCount = 0 # Counter of PSThread IDs generated so far
$PSThreadList = @{} # Existing PSThreads indexed by Id
Function Get-PSThread () {
Param(
[Parameter(Mandatory=$false, ValueFromPipeline=$true, Position=0)]
[int[]]$Id = $PSThreadList.Keys # List of thread IDs
)
$Id | % { $PSThreadList.$_ }
}
Function Start-PSThread () {
Param(
[Parameter(Mandatory=$true, Position=0)]
[ScriptBlock]$ScriptBlock, # The script block to run in a new thread
[Parameter(Mandatory=$false)]
[String]$Name = "", # Optional thread name. Default: "PSThread$Id"
[Parameter(Mandatory=$false)]
[String]$Event = "", # Optional thread completion event name. Default: None
[Parameter(Mandatory=$false)]
[Hashtable]$Variables = @{}, # Optional variables to copy into the script context.
[Parameter(Mandatory=$false)]
[String[]]$Functions = @(), # Optional functions to copy into the script context.
[Parameter(Mandatory=$false)]
[Object[]]$Arguments = @() # Optional arguments to pass to the script.
)
$Id = $script:PSThreadCount
$script:PSThreadCount += 1
if (!$Name.Length) {
$Name = "PSThread$Id"
}
$InitialSessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
foreach ($VarName in $Variables.Keys) { # Copy the specified variables into the script initial context
$value = $Variables.$VarName
Write-Debug "Adding variable $VarName=[$($Value.GetType())]$Value"
$var = New-Object System.Management.Automation.Runspaces.SessionStateVariableEntry($VarName, $value, "")
$InitialSessionState.Variables.Add($var)
}
foreach ($FuncName in $Functions) { # Copy the specified functions into the script initial context
$Body = Get-Content function:$FuncName
Write-Debug "Adding function $FuncName () {$Body}"
$func = New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry($FuncName, $Body)
$InitialSessionState.Commands.Add($func)
}
$RunSpace = [RunspaceFactory]::CreateRunspace($InitialSessionState)
$RunSpace.Open()
$PSPipeline = [powershell]::Create()
$PSPipeline.Runspace = $RunSpace
$PSPipeline.AddScript($ScriptBlock) | Out-Null
$Arguments | % {
Write-Debug "Adding argument [$($_.GetType())]'$_'"
$PSPipeline.AddArgument($_) | Out-Null
}
$Handle = $PSPipeline.BeginInvoke() # Start executing the script
if ($Event.Length) { # Do this after BeginInvoke(), to avoid getting the start event.
Register-ObjectEvent $PSPipeline -EventName InvocationStateChanged -SourceIdentifier $Name -MessageData $Event
}
$PSThread = New-Object PSObject -Property @{
Id = $Id
Name = $Name
Event = $Event
RunSpace = $RunSpace
PSPipeline = $PSPipeline
Handle = $Handle
} # Return the thread description variables
$script:PSThreadList[$Id] = $PSThread
$PSThread
}
#-----------------------------------------------------------------------------#
# #
# Function Receive-PSThread #
# #
# Description Get the result of a thread, and optionally clean it up #
# #
# Arguments See the Param() block #
# #
# Notes #
# #
# History #
# 2016-06-08 JFL Created this function #
# #
#-----------------------------------------------------------------------------#
Function Receive-PSThread () {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$false, ValueFromPipeline=$true, Position=0)]
[PSObject]$PSThread, # Thread descriptor object
[Parameter(Mandatory=$false)]
[Switch]$AutoRemove # If $True, remove the PSThread object
)
Process {
if ($PSThread.Event -and $AutoRemove) {
Unregister-Event -SourceIdentifier $PSThread.Name
Get-Event -SourceIdentifier $PSThread.Name | Remove-Event # Flush remaining events
}
try {
$PSThread.PSPipeline.EndInvoke($PSThread.Handle) # Output the thread pipeline output
} catch {
$_ # Output the thread pipeline error
}
if ($AutoRemove) {
$PSThread.RunSpace.Close()
$PSThread.PSPipeline.Dispose()
$PSThreadList.Remove($PSThread.Id)
}
}
}
Function Remove-PSThread () {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$false, ValueFromPipeline=$true, Position=0)]
[PSObject]$PSThread # Thread descriptor object
)
Process {
$_ | Receive-PSThread -AutoRemove | Out-Null
}
}
#-----------------------------------------------------------------------------#
# #
# Function Send-PipeMessage #
# #
# Description Send a message to a named pipe #
# #
# Arguments See the Param() block #
# #
# Notes #
# #
# History #
# 2016-05-25 JFL Created this function #
# #
#-----------------------------------------------------------------------------#
Function Send-PipeMessage () {
Param(
[Parameter(Mandatory=$true)]
[String]$PipeName, # Named pipe name
[Parameter(Mandatory=$true)]
[String]$Message # Message string
)
$PipeDir = [System.IO.Pipes.PipeDirection]::Out
$PipeOpt = [System.IO.Pipes.PipeOptions]::Asynchronous
$pipe = $null # Named pipe stream
$sw = $null # Stream Writer
try {
$pipe = new-object System.IO.Pipes.NamedPipeClientStream(".", $PipeName, $PipeDir, $PipeOpt)
$sw = new-object System.IO.StreamWriter($pipe)
$pipe.Connect(1000)
if (!$pipe.IsConnected) {
throw "Failed to connect client to pipe $pipeName"
}
$sw.AutoFlush = $true
$sw.WriteLine($Message)
} catch {
Log "Error sending pipe $pipeName message: $_"
} finally {
if ($sw) {
$sw.Dispose() # Release resources
$sw = $null # Force the PowerShell garbage collector to delete the .net object
}
if ($pipe) {
$pipe.Dispose() # Release resources
$pipe = $null # Force the PowerShell garbage collector to delete the .net object
}
}
}
#-----------------------------------------------------------------------------#
# #
# Function Receive-PipeMessage #
# #
# Description Wait for a message from a named pipe #
# #
# Arguments See the Param() block #
# #
# Notes I tried keeping the pipe open between client connections, #
# but for some reason everytime the client closes his end #
# of the pipe, this closes the server end as well. #
# Any solution on how to fix this would make the code #
# more efficient. #
# #
# History #
# 2016-05-25 JFL Created this function #
# #
#-----------------------------------------------------------------------------#
Function Receive-PipeMessage () {
Param(
[Parameter(Mandatory=$true)]
[String]$PipeName # Named pipe name
)
$PipeDir = [System.IO.Pipes.PipeDirection]::In
$PipeOpt = [System.IO.Pipes.PipeOptions]::Asynchronous
$PipeMode = [System.IO.Pipes.PipeTransmissionMode]::Message
try {
$pipe = $null # Named pipe stream
$pipe = New-Object system.IO.Pipes.NamedPipeServerStream($PipeName, $PipeDir, 1, $PipeMode, $PipeOpt)
$sr = $null # Stream Reader
$sr = new-object System.IO.StreamReader($pipe)
$pipe.WaitForConnection()
$Message = $sr.Readline()
$Message
} catch {
Log "Error receiving pipe message: $_"
} finally {
if ($sr) {
$sr.Dispose() # Release resources
$sr = $null # Force the PowerShell garbage collector to delete the .net object
}
if ($pipe) {
$pipe.Dispose() # Release resources
$pipe = $null # Force the PowerShell garbage collector to delete the .net object
}
}
}
#-----------------------------------------------------------------------------#
# #
# Function Start-PipeHandlerThread #
# #
# Description Start a new thread waiting for control messages on a pipe #
# #
# Arguments See the Param() block #
# #
# Notes The pipe handler script uses function Receive-PipeMessage.#
# This function must be copied into the thread context. #
# #
# The other functions and variables copied into that thread #
# context are not strictly necessary, but are useful for #
# debugging possible issues. #
# #
# History #
# 2016-06-07 JFL Created this function #
# #
#-----------------------------------------------------------------------------#
$pipeThreadName = "Control Pipe Handler"
Function Start-PipeHandlerThread () {
Param(
[Parameter(Mandatory=$true)]
[String]$pipeName, # Named pipe name
[Parameter(Mandatory=$false)]
[String]$Event = "ControlMessage" # Event message
)
Start-PSThread -Variables @{ # Copy variables required by function Log() into the thread context
logDir = $logDir
logFile = $logFile
currentUserName = $currentUserName
} -Functions Now, Log, Receive-PipeMessage -ScriptBlock {
Param($pipeName, $pipeThreadName)
try {
Receive-PipeMessage "$pipeName" # Blocks the thread until the next message is received from the pipe
} catch {
Log "$pipeThreadName # Error: $_"
throw $_ # Push the error back to the main thread
}
} -Name $pipeThreadName -Event $Event -Arguments $pipeName, $pipeThreadName
}
#-----------------------------------------------------------------------------#
# #
# Function Receive-PipeHandlerThread #
# #
# Description Get what the pipe handler thread received #
# #
# Arguments See the Param() block #
# #
# Notes #
# #
# History #
# 2016-06-07 JFL Created this function #
# #
#-----------------------------------------------------------------------------#
Function Receive-PipeHandlerThread () {
Param(
[Parameter(Mandatory=$true)]
[PSObject]$pipeThread # Thread descriptor
)
Receive-PSThread -PSThread $pipeThread -AutoRemove
}
#-----------------------------------------------------------------------------#
# #
# Function $source #
# #
# Description C# source of the PSService.exe stub #
# #
# Arguments #
# #
# Notes The lines commented with "SET STATUS" and "EVENT LOG" are #
# optional. (Or blocks between "// SET STATUS [" and #
# "// SET STATUS ]" comments.) #
# SET STATUS lines are useful only for services with a long #
# startup time. #
# EVENT LOG lines are useful for debugging the service. #
# #
# History #
# 2017-10-04 RBL Updated the OnStop() procedure adding the sections #
# try{ #
# }catch{ #
# }finally{ #
# } #
# This resolved the issue where stopping the service would #
# leave the PowerShell process -Service still running. This #
# unclosed process was an orphaned process that would #
# remain until the pid was manually killed or the computer #
# was rebooted #
# #
#-----------------------------------------------------------------------------#
$scriptCopyCname = $scriptCopy -replace "\\", "\\" # Double backslashes. (The first \\ is a regexp with \ escaped; The second is a plain string.)
$source = @"
using System;
using System.ServiceProcess;
using System.Diagnostics;
using System.Runtime.InteropServices; // SET STATUS
using System.ComponentModel; // SET STATUS
public enum ServiceType : int { // SET STATUS [
SERVICE_WIN32_OWN_PROCESS = 0x00000010,
SERVICE_WIN32_SHARE_PROCESS = 0x00000020,
}; // SET STATUS ]
public enum ServiceState : int { // SET STATUS [
SERVICE_STOPPED = 0x00000001,
SERVICE_START_PENDING = 0x00000002,
SERVICE_STOP_PENDING = 0x00000003,
SERVICE_RUNNING = 0x00000004,
SERVICE_CONTINUE_PENDING = 0x00000005,
SERVICE_PAUSE_PENDING = 0x00000006,
SERVICE_PAUSED = 0x00000007,
}; // SET STATUS ]
[StructLayout(LayoutKind.Sequential)] // SET STATUS [
public struct ServiceStatus {
public ServiceType dwServiceType;
public ServiceState dwCurrentState;
public int dwControlsAccepted;
public int dwWin32ExitCode;
public int dwServiceSpecificExitCode;
public int dwCheckPoint;
public int dwWaitHint;
}; // SET STATUS ]
public enum Win32Error : int { // WIN32 errors that we may need to use
NO_ERROR = 0,
ERROR_APP_INIT_FAILURE = 575,
ERROR_FATAL_APP_EXIT = 713,
ERROR_SERVICE_NOT_ACTIVE = 1062,
ERROR_EXCEPTION_IN_SERVICE = 1064,
ERROR_SERVICE_SPECIFIC_ERROR = 1066,
ERROR_PROCESS_ABORTED = 1067,
};
public class Service_$serviceName : ServiceBase { // $serviceName may begin with a digit; The class name must begin with a letter
private System.Diagnostics.EventLog eventLog; // EVENT LOG
private ServiceStatus serviceStatus; // SET STATUS
public Service_$serviceName() {
ServiceName = "$serviceName";
CanStop = true;
CanPauseAndContinue = false;
AutoLog = true;
eventLog = new System.Diagnostics.EventLog(); // EVENT LOG [
if (!System.Diagnostics.EventLog.SourceExists(ServiceName)) {
System.Diagnostics.EventLog.CreateEventSource(ServiceName, "$logName");
}
eventLog.Source = ServiceName;
eventLog.Log = "$logName"; // EVENT LOG ]
EventLog.WriteEntry(ServiceName, "$exeName $serviceName()"); // EVENT LOG
}
[DllImport("advapi32.dll", SetLastError=true)] // SET STATUS
private static extern bool SetServiceStatus(IntPtr handle, ref ServiceStatus serviceStatus);
protected override void OnStart(string [] args) {
EventLog.WriteEntry(ServiceName, "$exeName OnStart() // Entry. Starting script '$scriptCopyCname' -SCMStart"); // EVENT LOG
// Set the service state to Start Pending. // SET STATUS [
// Only useful if the startup time is long. Not really necessary here for a 2s startup time.
serviceStatus.dwServiceType = ServiceType.SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwWaitHint = 2000; // It takes about 2 seconds to start PowerShell
SetServiceStatus(ServiceHandle, ref serviceStatus); // SET STATUS ]
// Start a child process with another copy of this script
try {
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "PowerShell.exe";
p.StartInfo.Arguments = "-ExecutionPolicy Bypass -c & '$scriptCopyCname' -SCMStart"; // Works if path has spaces, but not if it contains ' quotes.
p.Start();
// Read the output stream first and then wait. (To avoid deadlocks says Microsoft!)
string output = p.StandardOutput.ReadToEnd();
// Wait for the completion of the script startup code, that launches the -Service instance
p.WaitForExit();
if (p.ExitCode != 0) throw new Win32Exception((int)(Win32Error.ERROR_APP_INIT_FAILURE));
// Success. Set the service state to Running. // SET STATUS
serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING; // SET STATUS
} catch (Exception e) {
EventLog.WriteEntry(ServiceName, "$exeName OnStart() // Failed to start $scriptCopyCname. " + e.Message, EventLogEntryType.Error); // EVENT LOG
// Change the service state back to Stopped. // SET STATUS [
serviceStatus.dwCurrentState = ServiceState.SERVICE_STOPPED;
Win32Exception w32ex = e as Win32Exception; // Try getting the WIN32 error code
if (w32ex == null) { // Not a Win32 exception, but maybe the inner one is...
w32ex = e.InnerException as Win32Exception;
}
if (w32ex != null) { // Report the actual WIN32 error
serviceStatus.dwWin32ExitCode = w32ex.NativeErrorCode;
} else { // Make up a reasonable reason
serviceStatus.dwWin32ExitCode = (int)(Win32Error.ERROR_APP_INIT_FAILURE);
} // SET STATUS ]
} finally {
serviceStatus.dwWaitHint = 0; // SET STATUS
SetServiceStatus(ServiceHandle, ref serviceStatus); // SET STATUS
EventLog.WriteEntry(ServiceName, "$exeName OnStart() // Exit"); // EVENT LOG
}
}
protected override void OnStop() {
EventLog.WriteEntry(ServiceName, "$exeName OnStop() // Entry"); // EVENT LOG
// Start a child process with another copy of ourselves
try {
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "PowerShell.exe";
p.StartInfo.Arguments = "-ExecutionPolicy Bypass -c & '$scriptCopyCname' -SCMStop"; // Works if path has spaces, but not if it contains ' quotes.
p.Start();
// Read the output stream first and then wait. (To avoid deadlocks says Microsoft!)
string output = p.StandardOutput.ReadToEnd();
// Wait for the PowerShell script to be fully stopped.
p.WaitForExit();
if (p.ExitCode != 0) throw new Win32Exception((int)(Win32Error.ERROR_APP_INIT_FAILURE));
// Success. Set the service state to Stopped. // SET STATUS
serviceStatus.dwCurrentState = ServiceState.SERVICE_STOPPED; // SET STATUS
} catch (Exception e) {
EventLog.WriteEntry(ServiceName, "$exeName OnStop() // Failed to stop $scriptCopyCname. " + e.Message, EventLogEntryType.Error); // EVENT LOG
// Change the service state back to Started. // SET STATUS [
serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
Win32Exception w32ex = e as Win32Exception; // Try getting the WIN32 error code
if (w32ex == null) { // Not a Win32 exception, but maybe the inner one is...
w32ex = e.InnerException as Win32Exception;
}
if (w32ex != null) { // Report the actual WIN32 error
serviceStatus.dwWin32ExitCode = w32ex.NativeErrorCode;
} else { // Make up a reasonable reason
serviceStatus.dwWin32ExitCode = (int)(Win32Error.ERROR_APP_INIT_FAILURE);
} // SET STATUS ]
} finally {
serviceStatus.dwWaitHint = 0; // SET STATUS
SetServiceStatus(ServiceHandle, ref serviceStatus); // SET STATUS
EventLog.WriteEntry(ServiceName, "$exeName OnStop() // Exit"); // EVENT LOG
}
}
public static void Main() {
System.ServiceProcess.ServiceBase.Run(new Service_$serviceName());
}
}
"@
#-----------------------------------------------------------------------------#
# #
# Function Main #
# #
# Description Execute the specified actions #
# #
# Arguments See the Param() block at the top of this script #
# #
# Notes #
# #
# History #
# #
#-----------------------------------------------------------------------------#
# Identify the user name. We use that for logging.
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$currentUserName = $identity.Name # Ex: "NT AUTHORITY\SYSTEM" or "Domain\Administrator"
if ($Setup) {Log ""} # Insert one blank line to separate test sessions logs
Log $MyInvocation.Line # The exact command line that was used to start us
# The following commands write to the event log, but we need to make sure the PSService source is defined.
New-EventLog -LogName $logName -Source $serviceName -ea SilentlyContinue
# Workaround for PowerShell v2 bug: $PSCmdlet Not yet defined in Param() block
$Status = ($PSCmdlet.ParameterSetName -eq 'Status')
if ($SCMStart) { # The SCM tells us to start the service
# Do whatever is necessary to start the service script instance
Log "$scriptName -SCMStart: Starting script '$scriptFullName' -Service"
Write-EventLog -LogName $logName -Source $serviceName -EventId 1001 -EntryType Information -Message "$scriptName -SCMStart: Starting script '$scriptFullName' -Service"
Start-Process PowerShell.exe -ArgumentList ("-c & '$scriptFullName' -Service")
return
}
if ($Start) { # The user tells us to start the service
Write-Verbose "Starting service $serviceName"
Write-EventLog -LogName $logName -Source $serviceName -EventId 1002 -EntryType Information -Message "$scriptName -Start: Starting service $serviceName"
Start-Service $serviceName # Ask Service Control Manager to start it
return
}
if ($SCMStop) { # The SCM tells us to stop the service
# Do whatever is necessary to stop the service script instance
Write-EventLog -LogName $logName -Source $serviceName -EventId 1003 -EntryType Information -Message "$scriptName -SCMStop: Stopping script $scriptName -Service"
Log "$scriptName -SCMStop: Stopping script $scriptName -Service"
# Send an exit message to the service instance
Send-PipeMessage $pipeName "exit"
return
}
if ($Stop) { # The user tells us to stop the service
Write-Verbose "Stopping service $serviceName"
Write-EventLog -LogName $logName -Source $serviceName -EventId 1004 -EntryType Information -Message "$scriptName -Stop: Stopping service $serviceName"
Stop-Service $serviceName # Ask Service Control Manager to stop it
return
}
if ($Restart) { # Restart the service
& $scriptFullName -Stop
& $scriptFullName -Start
return
}
if ($Status) { # Get the current service status
$spid = $null
$processes = @(Get-WmiObject Win32_Process -filter "Name = 'powershell.exe'" | Where-Object {
$_.CommandLine -match ".*$scriptCopyCname.*-Service"
})
foreach ($process in $processes) { # There should be just one, but be prepared for surprises.
$spid = $process.ProcessId
Write-Verbose "$serviceName Process ID = $spid"
}
# if (Test-Path "HKLM:\SYSTEM\CurrentControlSet\services\$serviceName") {}
try {
$pss = Get-Service $serviceName -ea stop # Will error-out if not installed
} catch {
"Not Installed"
return
}
$pss.Status
if (($pss.Status -eq "Running") -and (!$spid)) { # This happened during the debugging phase
Write-Error "The Service Control Manager thinks $serviceName is started, but $serviceName.ps1 -Service is not running."
exit 1
}
return
}
if ($Setup) { # Install the service
# Check if it's necessary
try {
$pss = Get-Service $serviceName -ea stop # Will error-out if not installed
# Check if this script is newer than the installed copy.
if ((Get-Item $scriptCopy -ea SilentlyContinue).LastWriteTime -lt (Get-Item $scriptFullName -ea SilentlyContinue).LastWriteTime) {
Write-Verbose "Service $serviceName is already Installed, but requires upgrade"
& $scriptFullName -Remove
throw "continue"
} else {
Write-Verbose "Service $serviceName is already Installed, and up-to-date"
}
exit 0
} catch {
# This is the normal case here. Do not throw or write any error!
Write-Debug "Installation is necessary" # Also avoids a ScriptAnalyzer warning
# And continue with the installation.
}
if (!(Test-Path $installDir)) {
New-Item -ItemType directory -Path $installDir | Out-Null
}
# Copy the service script into the installation directory
if ($ScriptFullName -ne $scriptCopy) {
Write-Verbose "Installing $scriptCopy"
Copy-Item $ScriptFullName $scriptCopy
}
# Generate the service .EXE from the C# source embedded in this script
try {
Write-Verbose "Compiling $exeFullName"
Add-Type -TypeDefinition $source -Language CSharp -OutputAssembly $exeFullName -OutputType ConsoleApplication -ReferencedAssemblies "System.ServiceProcess" -Debug:$false
} catch {
$msg = $_.Exception.Message
Write-error "Failed to create the $exeFullName service stub. $msg"
exit 1
}
# Register the service
Write-Verbose "Registering service $serviceName"
if ($UserName -and !$Credential.UserName) {
$emptyPassword = New-Object -Type System.Security.SecureString
switch ($UserName) {
{"LocalService", "NetworkService" -contains $_} {
$Credential = New-Object -Type System.Management.Automation.PSCredential ("NT AUTHORITY\$UserName", $emptyPassword)
}
{"LocalSystem", ".\LocalSystem", "${env:COMPUTERNAME}\LocalSystem", "NT AUTHORITY\LocalService", "NT AUTHORITY\NetworkService" -contains $_} {
$Credential = New-Object -Type System.Management.Automation.PSCredential ($UserName, $emptyPassword)
}
default {
if (!$Password) {
$Credential = Get-Credential -UserName $UserName -Message "Please enter the password for the service user"
} else {
$securePassword = ConvertTo-SecureString $Password -AsPlainText -Force
$Credential = New-Object -Type System.Management.Automation.PSCredential ($UserName, $securePassword)
}
}
}
}
if ($Credential.UserName) {
Log "$scriptName -Setup # Configuring the service to run as $($Credential.UserName)"
$pss = New-Service $serviceName $exeFullName -DisplayName $serviceDisplayName -Description $ServiceDescription -StartupType Automatic -Credential $Credential
} else {
Log "$scriptName -Setup # Configuring the service to run by default as LocalSystem"
$pss = New-Service $serviceName $exeFullName -DisplayName $serviceDisplayName -Description $ServiceDescription -StartupType Automatic
}
return
}
if ($Remove) { # Uninstall the service
# Check if it's necessary
try {
$pss = Get-Service $serviceName -ea stop # Will error-out if not installed
} catch {
Write-Verbose "Already uninstalled"
return
}
Stop-Service $serviceName # Make sure it's stopped
# In the absence of a Remove-Service applet, use sc.exe instead.
Write-Verbose "Removing service $serviceName"
$msg = sc.exe delete $serviceName
if ($LastExitCode) {
Write-Error "Failed to remove the service ${serviceName}: $msg"
exit 1
} else {
Write-Verbose $msg
}
# Remove the installed files
if (Test-Path $installDir) {
foreach ($ext in ("exe", "pdb", "ps1")) {
$file = "$installDir\$serviceName.$ext"
if (Test-Path $file) {
Write-Verbose "Deleting file $file"
Remove-Item $file
}
}
if (!(@(Get-ChildItem $installDir -ea SilentlyContinue)).Count) {
Write-Verbose "Removing directory $installDir"
Remove-Item $installDir
}
}
Log "" # Insert one blank line to separate test sessions logs
return
}
if ($Control) { # Send a control message to the service
Send-PipeMessage $pipeName $control
}
if ($Service) { # Run the service
Write-EventLog -LogName $logName -Source $serviceName -EventId 1005 -EntryType Information -Message "$scriptName -Service # Beginning background job"
# Do the service background job
try {
# Start the control pipe handler thread
$pipeThread = Start-PipeHandlerThread $pipeName -Event "ControlMessage"
######### TO DO: Implement your own service code here. ##########
###### Example that wakes up and logs a line every 10 sec: ######
# Start a one shot timer
$timerName = "Initial adjust time"
$period = 10 # seconds
$mytimer = new-object System.Timers.Timer
$mytimer.Interval = ($period * 1000) # Milliseconds
$mytimer.AutoReset = $false # Make it fire once
Register-ObjectEvent $mytimer -EventName Elapsed -SourceIdentifier $timerName -MessageData "TimerTick"
$mytimer.start() #
# Start a periodic timer
$timerName = "Sample service timer"
$period = 3600 # seconds
$timer = new-object System.Timers.Timer
$timer.Interval = ($period * 1000) # Milliseconds
$timer.AutoReset = $true # Make it fire repeatedly
Register-ObjectEvent $timer -EventName Elapsed -SourceIdentifier $timerName -MessageData "TimerTick"
$timer.start() # Must be stopped in the finally block
# Now enter the main service event loop
do { # Keep running until told to exit by the -Stop handler
$event = Wait-Event # Wait for the next incoming event
$source = $event.SourceIdentifier
$message = $event.MessageData
$eventTime = $event.TimeGenerated.TimeofDay
Write-Debug "Event at $eventTime from ${source}: $message"
$event | Remove-Event # Flush the event from the queue
switch ($message) {
"ControlMessage" { # Required. Message received by the control pipe thread
$state = $event.SourceEventArgs.InvocationStateInfo.state
Write-Debug "$script -Service # Thread $source state changed to $state"
switch ($state) {
"Completed" {
$message = Receive-PipeHandlerThread $pipeThread
Log "$scriptName -Service # Received control message: $Message"
if ($message -ne "exit") { # Start another thread waiting for control messages
$pipeThread = Start-PipeHandlerThread $pipeName -Event "ControlMessage"
}
}
"Failed" {
$error = Receive-PipeHandlerThread $pipeThread
Log "$scriptName -Service # $source thread failed: $error"
Start-Sleep 1 # Avoid getting too many errors
$pipeThread = Start-PipeHandlerThread $pipeName -Event "ControlMessage" # Retry
}
}
}
"TimerTick" { # Example. Periodic event generated for this example
$myhour = Get-Date -UFormat "%H"
$mystart = ([int]$myhour) - 1
if (([int]$mystart) -lt 0)
{
$mystart = ([int]$mystart) + 24
}
$mystop = ([int]$myhour) + 15
if (([int]$mystop) -gt 23)
{
$mystop = ([int]$mystop) - 24
}
Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings -Name ActiveHoursStart -Value $mystart
Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings -Name ActiveHoursEnd -Value $mystop
Log "$scriptName -Service # Changed activation hours to $mystart -> $mystop"
}
default { # Should not happen
Log "$scriptName -Service # Unexpected event from ${source}: $Message"
}
}
} while ($message -ne "exit")
} catch { # An exception occurred while runnning the service
$msg = $_.Exception.Message
$line = $_.InvocationInfo.ScriptLineNumber
Log "$scriptName -Service # Error at line ${line}: $msg"
} finally { # Invoked in all cases: Exception or normally by -Stop
# Cleanup the periodic timer used in the above example
Unregister-Event -SourceIdentifier $timerName
$timer.stop()
############### End of the service code example. ################
# Terminate the control pipe handler thread
Get-PSThread | Remove-PSThread # Remove all remaining threads
# Flush all leftover events (There may be some that arrived after we exited the while event loop, but before we unregistered the events)
$events = Get-Event | Remove-Event
# Log a termination event, no matter what the cause is.
Write-EventLog -LogName $logName -Source $serviceName -EventId 1006 -EntryType Information -Message "$script -Service # Exiting"
Log "$scriptName -Service # Exiting"
}
return
}
</blockquote>
</pre>
<div>
<br /></div>
dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com0tag:blogger.com,1999:blog-1082071635998277371.post-14154023302725716862019-05-29T06:54:00.002-07:002019-10-21T22:43:47.972-07:00EdgeRouter X VPN connection to mullvad.net UPDATED<h3 class="post-title entry-title" itemprop="name">
</h3>
<div class="post-title entry-title" itemprop="name">
NB: Network speed my be reduced after this. On my 100/100 line I got 35/35. "Unknown" reported 15/18.<br />
<br />
<br />
In an earlier post I documented a procedure for setting up a <a href="https://dephiox.blogspot.com/2018/05/edgerouter-x-v197hotfix4-vpn-connection.html" target="_blank">EdgeRouter X VPN connection</a> to mullvad.net .</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
Recently I had to repeat the procedure and found the files available at mullvad.net were different.</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
Choosing the android setup you got a file named something like "mullvad_config_xx.ovpn". The certificate itself are included inside this file.</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
1) Make sure the time on the edge router are correct(?). UTC were wrong for me when connecting from Sweden to Norway. NO/SE time zone worked OK.</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
2) In the "mullvad_config_xx.ovpn add the following to the line reading "auth-user-pass": " /config/auth/pass.txt"</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
3) Upload the "mullvad_config_xx.ovpn" to "/config".</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
4) Create a file in "/config/auth/" called "pass.txt" contaning the mullvad account number in line 1 and "m" in line 2. Some downloads from the mullvad.net site will contain this information in a file called pass.txt.</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
Then ssh into the router and configure the VPN:</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
#configure</div>
<div class="post-title entry-title" itemprop="name">
#set interfaces openvpn vtun0 config-file /config/mullvad_config_no.ovpn</div>
<div class="post-title entry-title" itemprop="name">
#commit</div>
<div class="post-title entry-title" itemprop="name">
#save</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
And in the GUI, under "Firewall/NAT", select "Add source NAT"</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
description -> "Mullvad VPN"</div>
<div class="post-title entry-title" itemprop="name">
outbound int-> vtun0</div>
<div class="post-title entry-title" itemprop="name">
Trans -> Masquerade</div>
<div class="post-title entry-title" itemprop="name">
Protocol -> All</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
And save.</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
The final adjustment is changing the DNS to the mullvad DNS:</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
#configure</div>
<div class="post-title entry-title" itemprop="name">
#set service dns forwarding name-server 193.138.218.74</div>
<div class="post-title entry-title" itemprop="name">
#commit</div>
<div class="post-title entry-title" itemprop="name">
#save</div>
<div class="post-title entry-title" itemprop="name">
<br /></div>
<div class="post-title entry-title" itemprop="name">
Finally, connect to the <a href="http://am.i.mullvad.net/" target="_blank">IAmMullvad</a> site and make sure everything is OK. </div>
dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com5tag:blogger.com,1999:blog-1082071635998277371.post-57074625840461442082018-11-18T01:58:00.000-08:002018-11-18T01:58:59.782-08:00Controlling a Yamaha V-RX657 reciever from KODIAfter fifteen years of use some of the buttons on the remote for my Yamaha V-RX657 began to work sporadicly. In fact, that happened years ago, even the learning remote have become reluctant in changing the volume. So I wanted a way to control it via <a href="https://kodi.tv/" target="_blank">KODI</a>.<br />
<br />
So I got myself some IR transistors and IR LEDs and breadboarded this circuit:<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGSD-pfe6p9pxbUx7aDOID7UugTcIdfL0jV1ZL0jYknCkibbGara9zJnyamtY2BubEiy8QP16_-rZ7nI9oOkR27YlJPzibSgQQOOGjnycDVJlygxcWUulZvHb0rHlb2DiWCq5Ey_1wesw/s1600/irtrans.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="279" data-original-width="217" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGSD-pfe6p9pxbUx7aDOID7UugTcIdfL0jV1ZL0jYknCkibbGara9zJnyamtY2BubEiy8QP16_-rZ7nI9oOkR27YlJPzibSgQQOOGjnycDVJlygxcWUulZvHb0rHlb2DiWCq5Ey_1wesw/s200/irtrans.jpg" width="155" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Image from learn.parallax.com</td></tr>
</tbody></table>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
And while tracking the voltage at VA3 with a Salea logic analyser I got plots like these:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIvfx_ja0-9pUU-2aTXD5uUp1_sV5Uk4dvcN2lJf2bfO__kJ_nld6-dTpHR02YaYI_3gv42dNcLwf0QXoZ5VBx8YU_XgRqe2pLl1w3nUvJyNkx52Snsc6IK2MuZh_UxYuKBYMparxSvvE/s1600/Capture.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="461" data-original-width="1336" height="220" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIvfx_ja0-9pUU-2aTXD5uUp1_sV5Uk4dvcN2lJf2bfO__kJ_nld6-dTpHR02YaYI_3gv42dNcLwf0QXoZ5VBx8YU_XgRqe2pLl1w3nUvJyNkx52Snsc6IK2MuZh_UxYuKBYMparxSvvE/s640/Capture.PNG" width="640" /></a></div>
<br />
<br />
Zooming in on each peak revealed this pattern:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGUxDUHEB4ua7jPyWivJHePp9bDDkHL4tzf9BjYk7J10zt7N1PHABV2FKB-bSq4PK4n88IHsm77R5nlMUvTiJBZLliuoAjgSFslvbhmhMQPslu-8rQrclhnUQ4a590PaNQyUIsk74_jO4/s1600/Capture2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="453" data-original-width="1351" height="214" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGUxDUHEB4ua7jPyWivJHePp9bDDkHL4tzf9BjYk7J10zt7N1PHABV2FKB-bSq4PK4n88IHsm77R5nlMUvTiJBZLliuoAjgSFslvbhmhMQPslu-8rQrclhnUQ4a590PaNQyUIsk74_jO4/s640/Capture2.PNG" width="640" /></a></div>
<br />
<br />
Combining this information and doing a duckduckgo revealed that this were the NEC1 protocol. Carrier is 38 kHz, there are 32 bits of data and a stop bit in each burst. Every burst starts with a 9 ms carrier on followed by 4.5 ms off. A pulse of 564 us followed by 564 us off is a "0". A pulse and 1692 us off is 1 one. And there is a last pulse indicating the end of the burst. Repeating commands, e.g. "Volume Up" can be done by a 40 ms delay followed by a 9 ms carrier on, 2.25 ms off and a stop bit. More repeats are done with a 96 ms delay instead of the original 40 ms delay.<br />
<br />
<code>
MDCDR 01011110101000011001001101101100<br />
DTVCBL 01011110101000010010101011010101<br />
VOLUP 01011110101000010101100010100111<br />
VOLDOWN 01011110101000011101100000100111<br />
PWRON 01011110101000011011100001000111<br />
PWROFF 01011110101000010111100010000111<br />
TUNER 01011110101000010110100010010111<br />
CD 01011110101000011010100001010111<br />
MUTE 01011110101000010011100011000111<br />
DVD 01011110101000011000001101111100<br />
VAUX 01011110101000011010101001010101<br />
VCR1 01011110101000011111000000001111<br />
DVRVCR2 01011110101000011100100000110111<br />
</code><br />
The PWRON, PWROFF and MUTE buttons did not work on my remote, but I found them on <a href="http://irdb.tk/" target="_blank">irdb.tk</a>. They had all of the codes.<br />
<br />
I then used some <a href="https://gist.github.com/EEVblog/6206934" target="_blank">eevblog</a> code to transmit this through a IR LED. The repeats for the volume controls are enough to change the volume 3 dB.<br />
<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4oTsQ_voeAPoXvbrbJQBHun9sKsqWUgJxYFgv3nqK0XU-s2B7uMu3PAu1me8-pK3fjHI5P6YTbiAP3-Y4ZoDvv5E84XiiOE2nTS53VnDL0Y_9S64ODfpHGcr7n9NckN-hHFlwHBZOvpY/s1600/LED-driver-circuit.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="368" data-original-width="338" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4oTsQ_voeAPoXvbrbJQBHun9sKsqWUgJxYFgv3nqK0XU-s2B7uMu3PAu1me8-pK3fjHI5P6YTbiAP3-Y4ZoDvv5E84XiiOE2nTS53VnDL0Y_9S64ODfpHGcr7n9NckN-hHFlwHBZOvpY/s320/LED-driver-circuit.png" width="293" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">http://www.learningaboutelectronics.com/Articles/LED-driver-circuit.php</td></tr>
</tbody></table>
<br />
<div style="background: #111111; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="background-color: #0f140f; color: #ff0007; font-style: italic; font-weight: bold;">#define IRLEDpin 2 </span><span style="background-color: #0f140f; color: #008800; font-style: italic;">//the arduino pin connected to IR LED to ground. HIGH=LED ON</span>
<span style="background-color: #0f140f; color: #ff0007; font-style: italic; font-weight: bold;">#define BITtime 560 </span><span style="background-color: #0f140f; color: #008800; font-style: italic;">//length of the carrier bit in microseconds 562</span>
<span style="background-color: #0f140f; color: #008800; font-style: italic;">//put your own code here - 4 bytes (ADDR1 | ADDR2 | COMMAND1 | COMMAND2)</span>
<span style="color: #cdcaa9; font-weight: bold;">unsigned</span> <span style="color: #cdcaa9; font-weight: bold;">long</span> <span style="color: white;">TVON</span> <span style="color: white;">=</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">b00100000110111110001000011101111;</span>
<span style="color: #cdcaa9; font-weight: bold;">unsigned</span> <span style="color: #cdcaa9; font-weight: bold;">long</span> <span style="color: white;">MDCDR</span> <span style="color: white;">=</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">b01011110101000011001001101101100;</span>
<span style="color: #cdcaa9; font-weight: bold;">unsigned</span> <span style="color: #cdcaa9; font-weight: bold;">long</span> <span style="color: white;">DTVCBL</span> <span style="color: white;">=</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">b01011110101000010010101011010101;</span>
<span style="color: #cdcaa9; font-weight: bold;">unsigned</span> <span style="color: #cdcaa9; font-weight: bold;">long</span> <span style="color: white;">VOLUP</span> <span style="color: white;">=</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">b01011110101000010101100010100111;</span>
<span style="color: #cdcaa9; font-weight: bold;">unsigned</span> <span style="color: #cdcaa9; font-weight: bold;">long</span> <span style="color: white;">VOLDOWN</span> <span style="color: white;">=</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">b01011110101000011101100000100111;</span>
<span style="color: #cdcaa9; font-weight: bold;">unsigned</span> <span style="color: #cdcaa9; font-weight: bold;">long</span> <span style="color: white;">PWRON</span> <span style="color: white;">=</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">b01011110101000011011100001000111;</span>
<span style="color: #cdcaa9; font-weight: bold;">unsigned</span> <span style="color: #cdcaa9; font-weight: bold;">long</span> <span style="color: white;">PWROFF</span> <span style="color: white;">=</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">b01011110101000010111100010000111;</span>
<span style="color: #cdcaa9; font-weight: bold;">unsigned</span> <span style="color: #cdcaa9; font-weight: bold;">long</span> <span style="color: white;">TUNER</span> <span style="color: white;">=</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">b01011110101000010110100010010111;</span>
<span style="color: #cdcaa9; font-weight: bold;">unsigned</span> <span style="color: #cdcaa9; font-weight: bold;">long</span> <span style="color: white;">CD</span> <span style="color: white;">=</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">b01011110101000011010100001010111;</span>
<span style="color: #cdcaa9; font-weight: bold;">unsigned</span> <span style="color: #cdcaa9; font-weight: bold;">long</span> <span style="color: white;">MUTE</span> <span style="color: white;">=</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">b01011110101000010011100011000111;</span>
<span style="color: #cdcaa9; font-weight: bold;">unsigned</span> <span style="color: #cdcaa9; font-weight: bold;">long</span> <span style="color: white;">DVD</span> <span style="color: white;">=</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">b01011110101000011000001101111100;</span>
<span style="color: #cdcaa9; font-weight: bold;">unsigned</span> <span style="color: #cdcaa9; font-weight: bold;">long</span> <span style="color: white;">VAUX</span> <span style="color: white;">=</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">b01011110101000011010101001010101;</span>
<span style="color: #cdcaa9; font-weight: bold;">unsigned</span> <span style="color: #cdcaa9; font-weight: bold;">long</span> <span style="color: white;">VCR1</span> <span style="color: white;">=</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">b01011110101000011111000000001111;</span>
<span style="color: #cdcaa9; font-weight: bold;">unsigned</span> <span style="color: #cdcaa9; font-weight: bold;">long</span> <span style="color: white;">DVRVCR2</span> <span style="color: white;">=</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">b01011110101000011100100000110111;</span>
<span style="color: #cdcaa9; font-weight: bold;">String</span> <span style="color: white;">serial_command=</span><span style="color: #0086d2;">""</span><span style="color: white;">;</span>
<span style="color: #cdcaa9; font-weight: bold;">void</span> <span style="color: white;">setup()</span>
<span style="color: white;">{</span>
<span style="color: #ff0086; font-weight: bold;">Serial</span><span style="color: white;">.</span><span style="color: #ff0086; font-weight: bold;">begin</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">9600</span><span style="color: white;">);</span>
<span style="color: #ff0086; font-weight: bold;">Serial</span><span style="color: white;">.</span><span style="color: #ff0086; font-weight: bold;">setTimeout</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">1000</span><span style="color: white;">);</span>
<span style="color: white;">IRsetup();</span><span style="background-color: #0f140f; color: #008800; font-style: italic;">//Only need to call this once to setup</span>
<span style="color: white;">}</span>
<span style="color: #cdcaa9; font-weight: bold;">void</span> <span style="color: #ff0086; font-weight: bold;">IRsetup</span><span style="color: white;">(</span><span style="color: #cdcaa9; font-weight: bold;">void</span><span style="color: white;">)</span>
<span style="color: white;">{</span>
<span style="color: #ff0086; font-weight: bold;">pinMode</span><span style="color: white;">(IRLEDpin,</span> <span style="color: #fb660a; font-weight: bold;">OUTPUT</span><span style="color: white;">);</span>
<span style="color: #ff0086; font-weight: bold;">digitalWrite</span><span style="color: white;">(IRLEDpin,</span> <span style="color: #fb660a; font-weight: bold;">LOW</span><span style="color: white;">);</span> <span style="background-color: #0f140f; color: #008800; font-style: italic;">//turn off IR LED to start</span>
<span style="color: white;">}</span>
<span style="background-color: #0f140f; color: #008800; font-style: italic;">// Ouput the 38KHz carrier frequency for the required time in microseconds</span>
<span style="background-color: #0f140f; color: #008800; font-style: italic;">// This is timing critial and just do-able on an Arduino using the standard I/O functions.</span>
<span style="background-color: #0f140f; color: #008800; font-style: italic;">// If you are using interrupts, ensure they disabled for the duration.</span>
<span style="color: #cdcaa9; font-weight: bold;">void</span> <span style="color: #ff0086; font-weight: bold;">IRcarrier</span><span style="color: white;">(</span><span style="color: #cdcaa9; font-weight: bold;">unsigned</span> <span style="color: #cdcaa9; font-weight: bold;">int</span> <span style="color: white;">IRtimemicroseconds)</span>
<span style="color: white;">{</span>
<span style="color: #fb660a; font-weight: bold;">for</span><span style="color: white;">(</span><span style="color: #cdcaa9; font-weight: bold;">int</span> <span style="color: white;">i=</span><span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">;</span> <span style="color: white;">i</span> <span style="color: white;"><</span> <span style="color: white;">(IRtimemicroseconds</span> <span style="color: white;">/</span> <span style="color: #0086f7; font-weight: bold;">26</span><span style="color: white;">);</span> <span style="color: white;">i++)</span>
<span style="color: white;">{</span>
<span style="color: #ff0086; font-weight: bold;">digitalWrite</span><span style="color: white;">(IRLEDpin,</span> <span style="color: #fb660a; font-weight: bold;">HIGH</span><span style="color: white;">);</span> <span style="background-color: #0f140f; color: #008800; font-style: italic;">//turn on the IR LED</span>
<span style="background-color: #0f140f; color: #008800; font-style: italic;">//NOTE: digitalWrite takes about 3.5us to execute, so we need to factor that into the timing.</span>
<span style="color: #ff0086; font-weight: bold;">delayMicroseconds</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">9</span><span style="color: white;">);</span> <span style="background-color: #0f140f; color: #008800; font-style: italic;">//delay for 13us (9us + digitalWrite), half the carrier frequnecy</span>
<span style="color: #ff0086; font-weight: bold;">digitalWrite</span><span style="color: white;">(IRLEDpin,</span> <span style="color: #fb660a; font-weight: bold;">LOW</span><span style="color: white;">);</span> <span style="background-color: #0f140f; color: #008800; font-style: italic;">//turn off the IR LED</span>
<span style="color: #ff0086; font-weight: bold;">delayMicroseconds</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">9</span><span style="color: white;">);</span> <span style="background-color: #0f140f; color: #008800; font-style: italic;">//delay for 13us (9us + digitalWrite), half the carrier frequnecy</span>
<span style="color: white;">}</span>
<span style="color: white;">}</span>
<span style="background-color: #0f140f; color: #008800; font-style: italic;">//Sends the IR code in 4 byte NEC format</span>
<span style="color: #cdcaa9; font-weight: bold;">void</span> <span style="color: #ff0086; font-weight: bold;">IRsendCode</span><span style="color: white;">(</span><span style="color: #cdcaa9; font-weight: bold;">unsigned</span> <span style="color: #cdcaa9; font-weight: bold;">long</span> <span style="color: white;">code)</span>
<span style="color: white;">{</span>
<span style="background-color: #0f140f; color: #008800; font-style: italic;">//send the leading pulse</span>
<span style="color: white;">IRcarrier(</span><span style="color: #0086f7; font-weight: bold;">9000</span><span style="color: white;">);</span> <span style="background-color: #0f140f; color: #008800; font-style: italic;">//9ms of carrier</span>
<span style="color: #ff0086; font-weight: bold;">delayMicroseconds</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">4500</span><span style="color: white;">);</span> <span style="background-color: #0f140f; color: #008800; font-style: italic;">//4.5ms of silence</span>
<span style="background-color: #0f140f; color: #008800; font-style: italic;">//send the user defined 4 byte/32bit code</span>
<span style="color: #fb660a; font-weight: bold;">for</span> <span style="color: white;">(</span><span style="color: #cdcaa9; font-weight: bold;">int</span> <span style="color: white;">i=</span><span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">;</span> <span style="color: white;">i<</span><span style="color: #0086f7; font-weight: bold;">32</span><span style="color: white;">;</span> <span style="color: white;">i++)</span>
<span style="color: white;">{</span>
<span style="color: white;">IRcarrier(BITtime);</span> <span style="background-color: #0f140f; color: #008800; font-style: italic;">//turn on the carrier for one bit time</span>
<span style="color: #fb660a; font-weight: bold;">if</span> <span style="color: white;">(code</span> <span style="color: white;">&</span> <span style="color: #0086f7; font-weight: bold;">0x80000000</span><span style="color: white;">)</span> <span style="background-color: #0f140f; color: #008800; font-style: italic;">//get the current bit by masking all but the MSB</span>
<span style="color: #ff0086; font-weight: bold;">delayMicroseconds</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">3</span> <span style="color: white;">*</span> <span style="color: white;">BITtime);</span> <span style="background-color: #0f140f; color: #008800; font-style: italic;">//a HIGH is 3 bit time periods</span>
<span style="color: #fb660a; font-weight: bold;">else</span>
<span style="color: #ff0086; font-weight: bold;">delayMicroseconds</span><span style="color: white;">(BITtime);</span>
<span style="color: white;">code<<=</span><span style="color: #0086f7; font-weight: bold;">1</span><span style="color: white;">;</span>
<span style="color: white;">}</span>
<span style="color: white;">IRcarrier(BITtime);</span> <span style="background-color: #0f140f; color: #008800; font-style: italic;">//STOP bit.</span>
<span style="color: white;">}</span>
<span style="color: #cdcaa9; font-weight: bold;">void</span> <span style="color: white;">loop()</span>
<span style="color: white;">{</span>
<span style="color: white;">serial_command=</span><span style="color: #0086d2;">""</span><span style="color: white;">;</span>
<span style="color: #fb660a; font-weight: bold;">if</span> <span style="color: white;">(</span><span style="color: #ff0086; font-weight: bold;">Serial</span><span style="color: white;">.</span><span style="color: #ff0086; font-weight: bold;">available</span><span style="color: white;">()></span><span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">)</span>
<span style="color: white;">{</span>
<span style="color: white;">serial_command</span> <span style="color: white;">=</span> <span style="color: #ff0086; font-weight: bold;">Serial</span><span style="color: white;">.</span><span style="color: #ff0086; font-weight: bold;">readString</span><span style="color: white;">();</span>
<span style="color: #fb660a; font-weight: bold;">if</span> <span style="color: white;">(serial_command.indexOf(</span><span style="color: #0086d2;">"PWRON"</span><span style="color: white;">)</span> <span style="color: white;">==</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">)</span>
<span style="color: white;">{</span>
<span style="color: white;">IRsendCode(PWRON);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">500</span><span style="color: white;">);</span>
<span style="color: white;">}</span>
<span style="color: #fb660a; font-weight: bold;">else</span> <span style="color: #fb660a; font-weight: bold;">if</span> <span style="color: white;">(serial_command.indexOf(</span><span style="color: #0086d2;">"PWROFF"</span><span style="color: white;">)</span> <span style="color: white;">==</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">)</span>
<span style="color: white;">{</span>
<span style="color: white;">IRsendCode(PWROFF);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">500</span><span style="color: white;">);</span>
<span style="color: white;">}</span>
<span style="color: #fb660a; font-weight: bold;">else</span> <span style="color: #fb660a; font-weight: bold;">if</span> <span style="color: white;">(serial_command.indexOf(</span><span style="color: #0086d2;">"TUNER"</span><span style="color: white;">)</span> <span style="color: white;">==</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">)</span>
<span style="color: white;">{</span>
<span style="color: white;">IRsendCode(TUNER);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">500</span><span style="color: white;">);</span>
<span style="color: white;">}</span>
<span style="color: #fb660a; font-weight: bold;">else</span> <span style="color: #fb660a; font-weight: bold;">if</span> <span style="color: white;">(serial_command.indexOf(</span><span style="color: #0086d2;">"CD"</span><span style="color: white;">)</span> <span style="color: white;">==</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">)</span>
<span style="color: white;">{</span>
<span style="color: white;">IRsendCode(CD);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">500</span><span style="color: white;">);</span>
<span style="color: white;">}</span>
<span style="color: #fb660a; font-weight: bold;">else</span> <span style="color: #fb660a; font-weight: bold;">if</span> <span style="color: white;">(serial_command.indexOf(</span><span style="color: #0086d2;">"MUTE"</span><span style="color: white;">)</span> <span style="color: white;">==</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">)</span>
<span style="color: white;">{</span>
<span style="color: white;">IRsendCode(MUTE);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">500</span><span style="color: white;">);</span>
<span style="color: white;">}</span>
<span style="color: #fb660a; font-weight: bold;">else</span> <span style="color: #fb660a; font-weight: bold;">if</span> <span style="color: white;">(serial_command.indexOf(</span><span style="color: #0086d2;">"DVD"</span><span style="color: white;">)</span> <span style="color: white;">==</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">)</span>
<span style="color: white;">{</span>
<span style="color: white;">IRsendCode(DVD);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">500</span><span style="color: white;">);</span>
<span style="color: white;">}</span>
<span style="color: #fb660a; font-weight: bold;">else</span> <span style="color: #fb660a; font-weight: bold;">if</span> <span style="color: white;">(serial_command.indexOf(</span><span style="color: #0086d2;">"VAUX"</span><span style="color: white;">)</span> <span style="color: white;">==</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">)</span>
<span style="color: white;">{</span>
<span style="color: white;">IRsendCode(VAUX);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">500</span><span style="color: white;">);</span>
<span style="color: white;">}</span>
<span style="color: #fb660a; font-weight: bold;">else</span> <span style="color: #fb660a; font-weight: bold;">if</span> <span style="color: white;">(serial_command.indexOf(</span><span style="color: #0086d2;">"VCR1"</span><span style="color: white;">)</span> <span style="color: white;">==</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">)</span>
<span style="color: white;">{</span>
<span style="color: white;">IRsendCode(VCR1);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">500</span><span style="color: white;">);</span>
<span style="color: white;">}</span>
<span style="color: #fb660a; font-weight: bold;">else</span> <span style="color: #fb660a; font-weight: bold;">if</span> <span style="color: white;">(serial_command.indexOf(</span><span style="color: #0086d2;">"DVRVCR2"</span><span style="color: white;">)</span> <span style="color: white;">==</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">)</span>
<span style="color: white;">{</span>
<span style="color: white;">IRsendCode(DVRVCR2);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">500</span><span style="color: white;">);</span>
<span style="color: white;">}</span>
<span style="color: #fb660a; font-weight: bold;">else</span> <span style="color: #fb660a; font-weight: bold;">if</span> <span style="color: white;">(serial_command.indexOf(</span><span style="color: #0086d2;">"MDCDR"</span><span style="color: white;">)</span> <span style="color: white;">==</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">)</span>
<span style="color: white;">{</span>
<span style="color: white;">IRsendCode(MDCDR);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">500</span><span style="color: white;">);</span>
<span style="color: white;">}</span>
<span style="color: #fb660a; font-weight: bold;">else</span> <span style="color: #fb660a; font-weight: bold;">if</span> <span style="color: white;">(serial_command.indexOf(</span><span style="color: #0086d2;">"DTVCBL"</span><span style="color: white;">)</span> <span style="color: white;">==</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">)</span>
<span style="color: white;">{</span>
<span style="color: white;">IRsendCode(DTVCBL);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">500</span><span style="color: white;">);</span>
<span style="color: white;">}</span>
<span style="color: #fb660a; font-weight: bold;">else</span> <span style="color: #fb660a; font-weight: bold;">if</span> <span style="color: white;">(serial_command.indexOf(</span><span style="color: #0086d2;">"VOLUP"</span><span style="color: white;">)</span> <span style="color: white;">==</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">)</span>
<span style="color: white;">{</span>
<span style="color: white;">IRsendCode(VOLUP);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">40</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(</span><span style="color: #0086f7; font-weight: bold;">9000</span><span style="color: white;">);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">2.25</span><span style="color: white;">);</span><span style="background-color: #0f140f; color: #008800; font-style: italic;">//2.23</span>
<span style="color: white;">IRcarrier(BITtime);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">96.28</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(</span><span style="color: #0086f7; font-weight: bold;">9000</span><span style="color: white;">);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">2.23</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(BITtime);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">96.28</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(</span><span style="color: #0086f7; font-weight: bold;">9000</span><span style="color: white;">);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">2.25</span><span style="color: white;">);</span><span style="background-color: #0f140f; color: #008800; font-style: italic;">//2.23</span>
<span style="color: white;">IRcarrier(BITtime);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">96.28</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(</span><span style="color: #0086f7; font-weight: bold;">9000</span><span style="color: white;">);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">2.23</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(BITtime);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">96.28</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(</span><span style="color: #0086f7; font-weight: bold;">9000</span><span style="color: white;">);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">2.23</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(BITtime);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">96.28</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(</span><span style="color: #0086f7; font-weight: bold;">9000</span><span style="color: white;">);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">2.23</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(BITtime);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">96.28</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(</span><span style="color: #0086f7; font-weight: bold;">9000</span><span style="color: white;">);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">2.23</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(BITtime);</span>
<span style="color: white;">}</span>
<span style="color: #fb660a; font-weight: bold;">else</span> <span style="color: #fb660a; font-weight: bold;">if</span> <span style="color: white;">(serial_command.indexOf(</span><span style="color: #0086d2;">"VOLDOWN"</span><span style="color: white;">)</span> <span style="color: white;">==</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">)</span>
<span style="color: white;">{</span>
<span style="color: white;">IRsendCode(VOLDOWN);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">40</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(</span><span style="color: #0086f7; font-weight: bold;">9000</span><span style="color: white;">);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">2.23</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(BITtime);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">96.28</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(</span><span style="color: #0086f7; font-weight: bold;">9000</span><span style="color: white;">);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">2.23</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(BITtime);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">96.28</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(</span><span style="color: #0086f7; font-weight: bold;">9000</span><span style="color: white;">);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">2.23</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(BITtime);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">96.28</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(</span><span style="color: #0086f7; font-weight: bold;">9000</span><span style="color: white;">);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">2.23</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(BITtime);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">96.28</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(</span><span style="color: #0086f7; font-weight: bold;">9000</span><span style="color: white;">);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">2.23</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(BITtime);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">96.28</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(</span><span style="color: #0086f7; font-weight: bold;">9000</span><span style="color: white;">);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">2.23</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(BITtime);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">96.28</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(</span><span style="color: #0086f7; font-weight: bold;">9000</span><span style="color: white;">);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">2.23</span><span style="color: white;">);</span>
<span style="color: white;">IRcarrier(BITtime);</span>
<span style="color: white;">}</span>
<span style="color: #fb660a; font-weight: bold;">else</span> <span style="color: #fb660a; font-weight: bold;">if</span> <span style="color: white;">(serial_command.indexOf(</span><span style="color: #0086d2;">"TVON"</span><span style="color: white;">)</span> <span style="color: white;">==</span> <span style="color: #0086f7; font-weight: bold;">0</span><span style="color: white;">)</span>
<span style="color: white;">{</span>
<span style="color: white;">IRsendCode(TVON);</span>
<span style="color: #ff0086; font-weight: bold;">delay</span><span style="color: white;">(</span><span style="color: #0086f7; font-weight: bold;">40</span><span style="color: white;">);</span>
<span style="color: white;">}</span>
<span style="color: white;">}</span>
<span style="color: white;">}</span>
</pre>
</div>
<br />
I used an old Arduino Nano and the 5V USB source on that board to power the LED.<br />
<br />
I then put the IR LED in front of the IR receiver on the amplifier.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7NppqP66lqU4dRFOfo3xyFaMUwnpuZaePczu4XYxu1C1MNpMro2mov4vbRcJjms4EkO-iccgv_tOOKSWLMxmJrqlVHdMwTogUIJBH15p-T2-VEpn2U2J8v00Ug-qDjQtRwHUguRujHXk/s1600/IMG_0970.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7NppqP66lqU4dRFOfo3xyFaMUwnpuZaePczu4XYxu1C1MNpMro2mov4vbRcJjms4EkO-iccgv_tOOKSWLMxmJrqlVHdMwTogUIJBH15p-T2-VEpn2U2J8v00Ug-qDjQtRwHUguRujHXk/s320/IMG_0970.JPG" width="320" /></a></div>
<br />
<br />
Connecting to the '/dev/ttyUSB0' port gave me a lot of trouble, it turned out that I had to wait 4 seconds from opening the port to actually using it. This made it clear that I had to create a system with a server controlling the serial port.<br />
<br />
<br />
<div style="background: #111111; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="background-color: #0f140f; color: #008800; font-style: italic;">#! /usr/bin/env python2</span>
<span style="background-color: #0f140f; color: #008800; font-style: italic;"># -*- coding: utf-8 -*-</span>
<span style="color: #fb660a; font-weight: bold;">import</span> <span style="color: white;">socket,</span> <span style="color: white;">sys,</span> <span style="color: white;">signal,</span> <span style="color: white;">serial,</span> <span style="color: white;">time</span>
<span style="color: white;">bytesize=</span><span style="color: #0086f7; font-weight: bold;">8</span>
<span style="color: white;">parity=</span><span style="color: #0086d2;">'N'</span>
<span style="color: white;">stopbits=</span><span style="color: #0086f7; font-weight: bold;">1</span>
<span style="color: white;">timeout=</span><span style="color: #0086f7; font-weight: bold;">3</span>
<span style="color: white;">port_name</span> <span style="color: white;">=</span> <span style="color: #0086d2;">'/dev/ttyUSB0'</span>
<span style="color: white;">ser</span> <span style="color: white;">=</span> <span style="color: white;">serial.Serial(port_name,</span> <span style="color: white;">baudrate=</span><span style="color: #0086f7; font-weight: bold;">9600</span><span style="color: white;">,</span> <span style="color: white;">bytesize=bytesize,</span> <span style="color: white;">parity=parity,</span> <span style="color: white;">stopbits=stopbits,</span> <span style="color: white;">timeout=timeout)</span>
<span style="color: white;">time.sleep(</span><span style="color: #0086f7; font-weight: bold;">4</span><span style="color: white;">)</span>
<span style="background-color: #0f140f; color: #008800; font-style: italic;">#print(ser.name) #which port</span>
<span style="color: white;">SOCKET_TIMEOUT</span> <span style="color: white;">=</span> <span style="color: #0086f7; font-weight: bold;">1</span>
<span style="color: white;">sigterm_exit</span> <span style="color: white;">=</span> <span style="color: white;">False</span>
<span style="color: #fb660a; font-weight: bold;">def</span> <span style="color: #ff0086; font-weight: bold;">exit_check</span><span style="color: white;">(_signo,</span> <span style="color: white;">_stack_frame):</span>
<span style="color: #fb660a; font-weight: bold;">global</span> <span style="color: white;">sigterm_exit</span>
<span style="color: white;">sigterm_exit</span> <span style="color: white;">=</span> <span style="color: white;">True</span>
<span style="color: white;">signal.signal(signal.SIGINT,</span> <span style="color: white;">exit_check)</span>
<span style="color: white;">signal.signal(signal.SIGTERM,</span> <span style="color: white;">exit_check)</span>
<span style="color: white;">sock</span> <span style="color: white;">=</span> <span style="color: white;">socket.socket(socket.AF_INET,</span> <span style="color: white;">socket.SOCK_DGRAM)</span>
<span style="color: white;">sock.setsockopt(socket.SOL_SOCKET,</span> <span style="color: white;">socket.SO_BROADCAST,</span> <span style="color: #0086f7; font-weight: bold;">1</span><span style="color: white;">)</span>
<span style="color: white;">sock.setsockopt(socket.SOL_SOCKET,</span> <span style="color: white;">socket.SO_REUSEADDR,</span> <span style="color: #0086f7; font-weight: bold;">1</span><span style="color: white;">)</span>
<span style="color: white;">sock.settimeout(SOCKET_TIMEOUT)</span>
<span style="color: white;">sock.bind((</span><span style="color: #0086d2;">''</span><span style="color: white;">,</span><span style="color: #0086f7; font-weight: bold;">31442</span><span style="color: white;">))</span>
<span style="color: #fb660a; font-weight: bold;">while</span> <span style="color: white;">not</span> <span style="color: white;">sigterm_exit:</span>
<span style="color: #fb660a; font-weight: bold;">try</span><span style="color: white;">:</span>
<span style="color: white;">msg,</span> <span style="color: white;">addr</span> <span style="color: white;">=</span> <span style="color: white;">sock.recvfrom(</span><span style="color: #0086f7; font-weight: bold;">1024</span><span style="color: white;">)</span>
<span style="color: #fb660a; font-weight: bold;">print</span> <span style="color: white;">time.ctime(),</span> <span style="color: white;">msg</span>
<span style="color: white;">ser.write(msg)</span>
<span style="color: white;">ser.flush()</span>
<span style="color: #fb660a; font-weight: bold;">except</span> <span style="color: white;">socket.timeout:</span>
<span style="color: #fb660a; font-weight: bold;">pass</span>
<span style="color: #fb660a; font-weight: bold;">except</span> <span style="color: white;">socket.error:</span> <span style="background-color: #0f140f; color: #008800; font-style: italic;"># prob the SIGINT, sigterm_exit is True now</span>
<span style="color: #fb660a; font-weight: bold;">pass</span>
<span style="color: white;">ser.close()</span>
<span style="color: #fb660a; font-weight: bold;">print</span> <span style="color: #0086d2;">'done'</span>
</pre>
</div>
<br />
This is a UDP server, listening at port 31442. It just relays commands to the serial port.<br />
<br />
The final steps is taken in KODI.<br />
<br />
At startup KODI now selects the sound channel KODI is playing through. This is the file 'autoexec.py' in '.kodi/userdata'.<br />
<br />
<br />
<div style="background: #111111; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #fb660a; font-weight: bold;">import</span> <span style="color: white;">socket</span>
<span style="color: #fb660a; font-weight: bold;">import</span> <span style="color: white;">xbmc</span>
<span style="color: white;">sock</span> <span style="color: white;">=</span> <span style="color: white;">socket.socket(socket.AF_INET,</span> <span style="color: white;">socket.SOCK_DGRAM)</span>
<span style="color: white;">addr</span> <span style="color: white;">=</span> <span style="color: white;">(</span><span style="color: #0086d2;">"127.0.0.1"</span><span style="color: white;">,</span> <span style="color: #0086f7; font-weight: bold;">31442</span><span style="color: white;">)</span>
<span style="color: white;">sock.sendto(</span><span style="color: #0086d2;">'DTVCBL'</span><span style="color: white;">,</span> <span style="color: white;">addr)</span> <span style="background-color: #0f140f; color: #008800; font-style: italic;">#this is the channel for kodi/youtube</span>
<span style="color: white;">sock.close()</span>
<span style="color: white;">xbmc.executebuiltin(</span><span style="color: #0086d2;">'ActivateWindow(Videos, Files)'</span><span style="color: white;">)</span>
</pre>
</div>
<br />
<br />
The last change were create a keymap file in '.kodi/userdata/keymaps'<br />
<br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #fb660a; font-weight: bold;"><keymap></span>
<span style="color: #fb660a; font-weight: bold;"><global></span>
<span style="color: #fb660a; font-weight: bold;"><keyboard></span>
<span style="color: #fb660a; font-weight: bold;"><numpadminus></span>RunScript(/home/pwr/.kodi/userdata/custom_IR.py, VOLDOWN)<span style="color: #fb660a; font-weight: bold;"></numpadminus></span>
<span style="color: #fb660a; font-weight: bold;"><numpadplus></span>RunScript(/home/pwr/.kodi/userdata/custom_IR.py, VOLUP)<span style="color: #fb660a; font-weight: bold;"></numpadplus></span>
<span style="color: #fb660a; font-weight: bold;"><numpadtimes></span>RunScript(/home/pwr/.kodi/userdata/custom_IR.py, DTVCBL)<span style="color: #fb660a; font-weight: bold;"></numpadtimes></span>
<span style="color: #fb660a; font-weight: bold;"></keyboard></span>
<span style="color: #fb660a; font-weight: bold;"></global></span>
<span style="color: #fb660a; font-weight: bold;"><FullscreenVideo></span>
<span style="color: #fb660a; font-weight: bold;"><keyboard></span>
<span style="color: #fb660a; font-weight: bold;"><numpadminus></span>RunScript(/home/pwr/.kodi/userdata/custom_IR.py, VOLDOWN)<span style="color: #fb660a; font-weight: bold;"></numpadminus></span>
<span style="color: #fb660a; font-weight: bold;"><numpadplus></span>RunScript(/home/pwr/.kodi/userdata/custom_IR.py, VOLUP)<span style="color: #fb660a; font-weight: bold;"></numpadplus></span>
<span style="color: #fb660a; font-weight: bold;"><numpadtimes></span>RunScript(/home/pwr/.kodi/userdata/custom_IR.py, DTVCBL)<span style="color: #fb660a; font-weight: bold;"></numpadtimes></span>
<span style="color: #fb660a; font-weight: bold;"></keyboard></span>
<span style="color: #fb660a; font-weight: bold;"></FullscreenVideo></span>
<span style="color: #fb660a; font-weight: bold;"></keymap></span>
</pre>
</div>
<br />
<br />dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com0tag:blogger.com,1999:blog-1082071635998277371.post-34670458694740678872018-10-18T05:17:00.001-07:002018-10-18T05:39:23.437-07:00Logging tellsticknet output to a database on ubuntu 18.04LTSI have a wind sensor on the outside of my house, but it is not placed in an optimal location. So I decided to get some data from the sensor and try to correlate it with the meteorological forecast.<br />
<br />
The <a href="https://pypi.org/project/MySQL-python/" target="_blank">MySQLdb</a>
package is used for MySQL access. Create a MySQL user and database
named "weather_logger". My current tables are listed as python comments below.<br />
<br />
<br />
The script listens for the sigterm signal from systemctl and has some error handlers for network failures. It will write information from these events into the "error_logger" table.<br />
<br />
The approach is based on this older <a href="http://dephiox.blogspot.com/2016/11/local-access-to-tellstick-net-via-python.html" target="_blank">post</a>. It assumes one tellsticknet unit in the network. If there are more, replace the tellsticknet discovery string <span style="background-color: #fff0f0;">'<broadcast>' with the ip address of the tellsticknet unit.</span> It does not care about the rolling code (id) of the sensors as well, even if it puts this information into the MySQL database.<br />
<br />
The optimal approach for this script could be to remove all sensor knowledge and just put every string collected into the "unknown_logger" table for others to process.<br />
<br />
This script is run at startup of the system by a systemd file, "/lib/systemd/system/tellsticknet.service".<br />
<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 100%; margin: 0;"><span style="color: #333333; font-size: xx-small;">[</span><span style="font-size: xx-small;">Unit<span style="color: #333333;">]</span>
<span style="color: #996633;">Description</span><span style="color: #333333;">=</span>Read oregon sensorvalues from tellsticknet and save in mysql db
<span style="color: #996633;">After</span><span style="color: #333333;">=</span>multi-user.target
<span style="color: #333333;">[</span>Service<span style="color: #333333;">]</span>
<span style="color: #996633;">Type</span><span style="color: #333333;">=</span>idle
<span style="color: #996633;">ExecStart</span><span style="color: #333333;">=</span>/usr/bin/python /home/<myuser>/tellsticknet_service/tellsticknet.py
<span style="color: #333333;">[</span>Install<span style="color: #333333;">]</span>
<span style="color: #996633;">WantedBy</span><span style="color: #333333;">=</span>multi-user.target
</span></pre>
</div>
<br />
<br />
<br />
<span style="font-size: xx-small;">(html by <a href="http://hilite.me/" target="_blank">hilite.me</a>)</span><br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; font-size: xx-small; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #888888;">#! /usr/bin/env python2</span>
<span style="color: #888888;"># -*- coding: utf-8 -*-</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">socket</span>
<span style="color: #008800; font-weight: bold;">from</span> <span style="color: #0e84b5; font-weight: bold;">datetime</span> <span style="color: #008800; font-weight: bold;">import</span> timedelta, datetime
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">time</span><span style="color: #333333;">,</span> <span style="color: #0e84b5; font-weight: bold;">sys</span><span style="color: #333333;">,</span> <span style="color: #0e84b5; font-weight: bold;">os</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">MySQLdb</span>
<span style="color: #008800; font-weight: bold;">import</span> <span style="color: #0e84b5; font-weight: bold;">signal</span>
<span style="color: #008800; font-weight: bold;">from</span> <span style="color: #0e84b5; font-weight: bold;">sensors</span> <span style="color: #008800; font-weight: bold;">import</span> <span style="color: #333333;">*</span>
sigterm_exit <span style="color: #333333;">=</span> <span style="color: #007020;">False</span>
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">exit_check</span>(_signo, _stack_frame):
<span style="color: #008800; font-weight: bold;">global</span> sigterm_exit
sigterm_exit <span style="color: #333333;">=</span> <span style="color: #007020;">True</span>
<span style="color: #888888;"># CREATE TABLE `weather_logger`.`temperature_logger` ( `ID` INT NOT NULL AUTO_INCREMENT,</span>
<span style="color: #888888;"># `sensorID` INT UNSIGNED NULL DEFAULT NULL , `datetime` DATETIME NULL DEFAULT NULL ,</span>
<span style="color: #888888;"># `temperature` FLOAT NULL DEFAULT NULL , `humidity` FLOAT NULL DEFAULT NULL,</span>
<span style="color: #888888;"># `battery` TINYINT NULL DEFAULT NULL, PRIMARY KEY (`ID`)) ENGINE = InnoDB;</span>
<span style="color: #888888;"># CREATE TABLE `weather_logger`.`wind_logger` ( `ID` INT NOT NULL AUTO_INCREMENT,</span>
<span style="color: #888888;"># `sensorID` INT UNSIGNED NULL DEFAULT NULL , `datetime` DATETIME NULL DEFAULT NULL ,</span>
<span style="color: #888888;"># `wind` FLOAT NULL DEFAULT NULL , `gust` FLOAT NULL DEFAULT NULL, `direction` FLOAT NULL DEFAULT NULL,</span>
<span style="color: #888888;"># `battery` TINYINT NULL DEFAULT NULL, PRIMARY KEY (`ID`)) ENGINE = InnoDB;</span>
<span style="color: #888888;"># CREATE TABLE `weather_logger`.`unknown_logger` ( `ID` INT NOT NULL AUTO_INCREMENT,</span>
<span style="color: #888888;"># `datetime` DATETIME NULL DEFAULT NULL , `data` VARCHAR(2048) NULL DEFAULT NULL,</span>
<span style="color: #888888;"># PRIMARY KEY (`ID`)) ENGINE = InnoDB;</span>
<span style="color: #888888;"># CREATE TABLE `weather_logger`.`error_logger` ( `ID` INT NOT NULL AUTO_INCREMENT,</span>
<span style="color: #888888;"># `datetime` DATETIME NULL DEFAULT NULL , `data` VARCHAR(2048) NULL DEFAULT NULL,</span>
<span style="color: #888888;"># PRIMARY KEY (`ID`)) ENGINE = InnoDB;</span>
<span style="color: #888888;">#</span>
<span style="color: #888888;"># CREATE TABLE `weather_logger`.`raw` ( `ID` INT NOT NULL AUTO_INCREMENT,</span>
<span style="color: #888888;"># `datetime` DATETIME NULL DEFAULT NULL , `raw_data` VARCHAR(1024) NULL DEFAULT NULL,</span>
<span style="color: #888888;"># PRIMARY KEY (`ID`)) ENGINE = InnoDB;</span>
signal<span style="color: #333333;">.</span>signal(signal<span style="color: #333333;">.</span>SIGINT, exit_check)
signal<span style="color: #333333;">.</span>signal(signal<span style="color: #333333;">.</span>SIGTERM, exit_check)
MYSQLHOST <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'10.0.0.7'</span>
SOCKET_TIMEOUT <span style="color: #333333;">=</span> timedelta(seconds<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">5</span>)
REG_INT <span style="color: #333333;">=</span> timedelta(minutes <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">10</span>)
db <span style="color: #333333;">=</span> MySQLdb<span style="color: #333333;">.</span>connect(host<span style="color: #333333;">=</span>MYSQLHOST, user<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">"weather_logger"</span>,
passwd<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">"weather_logger"</span>, db<span style="color: #333333;">=</span><span style="background-color: #fff0f0;">"weather_logger"</span>)
cur <span style="color: #333333;">=</span> db<span style="color: #333333;">.</span>cursor()
date_t <span style="color: #333333;">=</span> time<span style="color: #333333;">.</span>strftime(<span style="background-color: #fff0f0;">"%Y-%m-</span><span style="background-color: #eeeeee;">%d</span><span style="background-color: #fff0f0;"> %H:%M:%S"</span>, time<span style="color: #333333;">.</span>localtime())
sql <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'insert into error_logger values(NULL,</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #eeeeee;">%s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #fff0f0;">, </span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #eeeeee;">%s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #fff0f0;">)'</span><span style="color: #333333;">%</span>(date_t, <span style="background-color: #fff0f0;">"Starting tellsticknet logging"</span>)
cur<span style="color: #333333;">.</span>execute(sql)
db<span style="color: #333333;">.</span>commit()
sock <span style="color: #333333;">=</span> socket<span style="color: #333333;">.</span>socket(socket<span style="color: #333333;">.</span>AF_INET, socket<span style="color: #333333;">.</span>SOCK_DGRAM)
sock<span style="color: #333333;">.</span>setsockopt(socket<span style="color: #333333;">.</span>SOL_SOCKET, socket<span style="color: #333333;">.</span>SO_BROADCAST, <span style="color: #0000dd; font-weight: bold;">1</span>)
sock<span style="color: #333333;">.</span>setsockopt(socket<span style="color: #333333;">.</span>SOL_SOCKET, socket<span style="color: #333333;">.</span>SO_REUSEADDR, <span style="color: #0000dd; font-weight: bold;">1</span>)
sock<span style="color: #333333;">.</span>settimeout(SOCKET_TIMEOUT<span style="color: #333333;">.</span>seconds)
sock<span style="color: #333333;">.</span>bind((<span style="background-color: #fff0f0;">''</span>,<span style="color: #0000dd; font-weight: bold;">42314</span>))
comm_ok <span style="color: #333333;">=</span> <span style="color: #007020;">False</span>
<span style="color: #008800; font-weight: bold;">while</span> <span style="color: black; font-weight: bold;">not</span> comm_ok:
<span style="color: #008800; font-weight: bold;">if</span> sigterm_exit:
db<span style="color: #333333;">.</span>close()
sock<span style="color: #333333;">.</span>close()
sys<span style="color: #333333;">.</span>exit(<span style="color: #0000dd; font-weight: bold;">0</span>)
<span style="color: #008800; font-weight: bold;">try</span>:
sock<span style="color: #333333;">.</span>sendto(b<span style="background-color: #fff0f0;">'D'</span>, (<span style="background-color: #fff0f0;">'<broadcast>'</span>, <span style="color: #0000dd; font-weight: bold;">30303</span>))
data, (tellsticknetip, port) <span style="color: #333333;">=</span> sock<span style="color: #333333;">.</span>recvfrom(<span style="color: #0000dd; font-weight: bold;">2048</span>)
comm_ok <span style="color: #333333;">=</span> <span style="color: #007020;">True</span>
<span style="color: #008800; font-weight: bold;">except</span> socket<span style="color: #333333;">.</span>error: <span style="color: #888888;"># power out? try again:</span>
date_t <span style="color: #333333;">=</span> time<span style="color: #333333;">.</span>strftime(<span style="background-color: #fff0f0;">"%Y-%m-</span><span style="background-color: #eeeeee;">%d</span><span style="background-color: #fff0f0;"> %H:%M:%S"</span>, time<span style="color: #333333;">.</span>localtime())
sql <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'insert into error_logger values(NULL,</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #eeeeee;">%s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #fff0f0;">, </span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #eeeeee;">%s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #fff0f0;">)'</span><span style="color: #333333;">%</span>(date_t, <span style="background-color: #fff0f0;">"No connection with TellstickNet from init"</span>)
cur<span style="color: #333333;">.</span>execute(sql)
db<span style="color: #333333;">.</span>commit()
last_reg_listener <span style="color: #333333;">=</span> datetime<span style="color: #333333;">.</span>now() <span style="color: #333333;">-</span> REG_INT
<span style="color: #008800; font-weight: bold;">while</span> <span style="color: black; font-weight: bold;">not</span> sigterm_exit:
<span style="color: #008800; font-weight: bold;">if</span> datetime<span style="color: #333333;">.</span>now() <span style="color: #333333;">-</span> last_reg_listener <span style="color: #333333;">></span> REG_INT:
comm_ok <span style="color: #333333;">=</span> <span style="color: #007020;">False</span>
<span style="color: #008800; font-weight: bold;">while</span> <span style="color: black; font-weight: bold;">not</span> comm_ok:
<span style="color: #008800; font-weight: bold;">if</span> sigterm_exit:
db<span style="color: #333333;">.</span>close()
sock<span style="color: #333333;">.</span>close()
sys<span style="color: #333333;">.</span>exit(<span style="color: #0000dd; font-weight: bold;">0</span>)
<span style="color: #008800; font-weight: bold;">try</span>:
sock<span style="color: #333333;">.</span>sendto(<span style="background-color: #fff0f0;">"B:reglistener"</span>, (tellsticknetip, <span style="color: #0000dd; font-weight: bold;">42314</span>))
comm_ok <span style="color: #333333;">=</span> <span style="color: #007020;">True</span>
<span style="color: #008800; font-weight: bold;">except</span>:
date_t <span style="color: #333333;">=</span> time<span style="color: #333333;">.</span>strftime(<span style="background-color: #fff0f0;">"%Y-%m-</span><span style="background-color: #eeeeee;">%d</span><span style="background-color: #fff0f0;"> %H:%M:%S"</span>, time<span style="color: #333333;">.</span>localtime())
sql <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'insert into error_logger values(NULL,</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #eeeeee;">%s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #fff0f0;">, </span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #eeeeee;">%s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #fff0f0;">)'</span><span style="color: #333333;">%</span>(date_t, <span style="background-color: #fff0f0;">"No connection with TellstickNet from reglistener"</span>)
cur<span style="color: #333333;">.</span>execute(sql)
db<span style="color: #333333;">.</span>commit()
last_reg_listener <span style="color: #333333;">=</span> datetime<span style="color: #333333;">.</span>now()
<span style="color: #008800; font-weight: bold;">try</span>:
data,(address, port) <span style="color: #333333;">=</span> sock<span style="color: #333333;">.</span>recvfrom(<span style="color: #0000dd; font-weight: bold;">2048</span>)
<span style="color: #008800; font-weight: bold;">if</span> (data<span style="color: #333333;">.</span>split(<span style="background-color: #fff0f0;">":"</span>)[<span style="color: #0000dd; font-weight: bold;">6</span>][<span style="color: #0000dd; font-weight: bold;">6</span>:<span style="color: #0000dd; font-weight: bold;">10</span>]<span style="color: #333333;">==</span><span style="background-color: #fff0f0;">"F824"</span>):
(rc, temp,hum, batt) <span style="color: #333333;">=</span> decodeF824(data<span style="color: #333333;">.</span>split(<span style="background-color: #fff0f0;">":"</span>)[<span style="color: #0000dd; font-weight: bold;">7</span>][<span style="color: #0000dd; font-weight: bold;">5</span>:<span style="color: #0000dd; font-weight: bold;">5</span><span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">14</span>])
date_t <span style="color: #333333;">=</span> time<span style="color: #333333;">.</span>strftime(<span style="background-color: #fff0f0;">"%Y-%m-</span><span style="background-color: #eeeeee;">%d</span><span style="background-color: #fff0f0;"> %H:%M:%S"</span>, time<span style="color: #333333;">.</span>localtime())
sql <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'insert into temperature_logger values(NULL,</span><span style="background-color: #eeeeee;">%d</span><span style="background-color: #fff0f0;">,</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #eeeeee;">%s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #fff0f0;">, </span><span style="background-color: #eeeeee;">%f</span><span style="background-color: #fff0f0;">,</span><span style="background-color: #eeeeee;">%f</span><span style="background-color: #fff0f0;">, </span><span style="background-color: #eeeeee;">%d</span><span style="background-color: #fff0f0;">)'</span><span style="color: #333333;">%</span>(rc, date_t, temp, hum, <span style="color: #007020;">int</span>(batt))
<span style="color: #888888;">#print(sql)</span>
cur<span style="color: #333333;">.</span>execute(sql)
db<span style="color: #333333;">.</span>commit()
<span style="color: #008800; font-weight: bold;">elif</span> (data<span style="color: #333333;">.</span>split(<span style="background-color: #fff0f0;">":"</span>)[<span style="color: #0000dd; font-weight: bold;">6</span>][<span style="color: #0000dd; font-weight: bold;">6</span>:<span style="color: #0000dd; font-weight: bold;">10</span>]<span style="color: #333333;">==</span><span style="background-color: #fff0f0;">"1984"</span>):
(rc, w, wg, direction, batt) <span style="color: #333333;">=</span> decode1984(data<span style="color: #333333;">.</span>split(<span style="background-color: #fff0f0;">":"</span>)[<span style="color: #0000dd; font-weight: bold;">7</span>][<span style="color: #0000dd; font-weight: bold;">5</span>:<span style="color: #0000dd; font-weight: bold;">5</span><span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">16</span>])
date_t <span style="color: #333333;">=</span> time<span style="color: #333333;">.</span>strftime(<span style="background-color: #fff0f0;">"%Y-%m-</span><span style="background-color: #eeeeee;">%d</span><span style="background-color: #fff0f0;"> %H:%M:%S"</span>, time<span style="color: #333333;">.</span>localtime())
sql <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'insert into wind_logger values(NULL,</span><span style="background-color: #eeeeee;">%d</span><span style="background-color: #fff0f0;">,</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #eeeeee;">%s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #fff0f0;">, </span><span style="background-color: #eeeeee;">%f</span><span style="background-color: #fff0f0;">,</span><span style="background-color: #eeeeee;">%f</span><span style="background-color: #fff0f0;">,</span><span style="background-color: #eeeeee;">%f</span><span style="background-color: #fff0f0;">, </span><span style="background-color: #eeeeee;">%d</span><span style="background-color: #fff0f0;">)'</span><span style="color: #333333;">%</span>(rc, date_t, w, wg, direction, <span style="color: #007020;">int</span>(batt))
cur<span style="color: #333333;">.</span>execute(sql)
db<span style="color: #333333;">.</span>commit()
<span style="color: #008800; font-weight: bold;">else</span>:
date_t <span style="color: #333333;">=</span> time<span style="color: #333333;">.</span>strftime(<span style="background-color: #fff0f0;">"%Y-%m-</span><span style="background-color: #eeeeee;">%d</span><span style="background-color: #fff0f0;"> %H:%M:%S"</span>, time<span style="color: #333333;">.</span>localtime())
sql <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'insert into unknown_logger values(NULL,</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #eeeeee;">%s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #fff0f0;">, </span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #eeeeee;">%s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #fff0f0;">)'</span><span style="color: #333333;">%</span>(date_t, data)
cur<span style="color: #333333;">.</span>execute(sql)
db<span style="color: #333333;">.</span>commit()
<span style="color: #008800; font-weight: bold;">except</span> socket<span style="color: #333333;">.</span>timeout: <span style="color: #888888;"># time out, try again</span>
<span style="color: #008800; font-weight: bold;">pass</span>
<span style="color: #008800; font-weight: bold;">except</span> socket<span style="color: #333333;">.</span>error: <span style="color: #888888;">#power fail?</span>
date_t <span style="color: #333333;">=</span> time<span style="color: #333333;">.</span>strftime(<span style="background-color: #fff0f0;">"%Y-%m-</span><span style="background-color: #eeeeee;">%d</span><span style="background-color: #fff0f0;"> %H:%M:%S"</span>, time<span style="color: #333333;">.</span>localtime())
<span style="color: #008800; font-weight: bold;">if</span> sigterm_exit:
sql <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'insert into error_logger values(NULL,</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #eeeeee;">%s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #fff0f0;">, </span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #eeeeee;">%s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #fff0f0;">)'</span><span style="color: #333333;">%</span>(date_t, <span style="background-color: #fff0f0;">"sigterm recived"</span>)
cur<span style="color: #333333;">.</span>execute(sql)
db<span style="color: #333333;">.</span>commit()
<span style="color: #008800; font-weight: bold;">break</span>
<span style="color: #008800; font-weight: bold;">else</span>:
sql <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'insert into error_logger values(NULL,</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #eeeeee;">%s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #fff0f0;">, </span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #eeeeee;">%s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #fff0f0;">)'</span><span style="color: #333333;">%</span>(date_t, <span style="background-color: #fff0f0;">"No connection with TellstickNet from main loop"</span>)
cur<span style="color: #333333;">.</span>execute(sql)
db<span style="color: #333333;">.</span>commit()
<span style="color: #008800; font-weight: bold;">except</span>:
date_t <span style="color: #333333;">=</span> time<span style="color: #333333;">.</span>strftime(<span style="background-color: #fff0f0;">"%Y-%m-</span><span style="background-color: #eeeeee;">%d</span><span style="background-color: #fff0f0;"> %H:%M:%S"</span>, time<span style="color: #333333;">.</span>localtime())
sql <span style="color: #333333;">=</span> <span style="background-color: #fff0f0;">'insert into error_logger values(NULL,</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #eeeeee;">%s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #fff0f0;">, </span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #eeeeee;">%s</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\"</span><span style="background-color: #fff0f0;">)'</span><span style="color: #333333;">%</span>(date_t, sys<span style="color: #333333;">.</span>exc_info()[<span style="color: #0000dd; font-weight: bold;">0</span>])
cur<span style="color: #333333;">.</span>execute(sql)
db<span style="color: #333333;">.</span>commit()
<span style="color: #888888;">#got SIGTERM</span>
db<span style="color: #333333;">.</span>close()
sock<span style="color: #333333;">.</span>close()
</pre>
</div>
<br />
<br />
The "sensors.py" file used:<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; font-size: xx-small; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 100%; margin: 0;"><span style="color: #888888;">#some sensors from telldus-core/service/</span>
<span style="color: #888888;"># this code depends on signal checking done in the tellsticknet</span>
<span style="color: #888888;">#</span>
<span style="color: #888888;">#</span>
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">decode2914</span>(inp):
<span style="color: #888888;">#source:telldus-core/service/ProtocolOregon.cpp@c9567f</span>
<span style="color: #888888;">#// rain</span>
value <span style="color: #333333;">=</span> <span style="color: #007020;">int</span>(inp, <span style="color: #0000dd; font-weight: bold;">16</span>)
messageChecksum1 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
messageChecksum2 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
totRain1 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
totRain2 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
totRain3 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
totRain4 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
totRain5 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
totRain6 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
rainRate1 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
rainRate2 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
rainRate3 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
rainRate4 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
battery <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span> <span style="color: #888888;">#// PROBABLY battery</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
rollingcode <span style="color: #333333;">=</span> ((value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">+</span> (value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>)
checksum <span style="color: #333333;">=</span> ((value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">+</span> (value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>)
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">8</span>
channel <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
checksum <span style="color: #333333;">=</span> checksum <span style="color: #333333;">+</span> totRain1 <span style="color: #333333;">+</span> totRain2 <span style="color: #333333;">+</span> totRain3 <span style="color: #333333;">+</span> totRain4 <span style="color: #333333;">+</span> totRain5 <span style="color: #333333;">+</span> totRain6 <span style="color: #333333;">+</span>\
rainRate1 <span style="color: #333333;">+</span> rainRate2 <span style="color: #333333;">+</span> rainRate3 <span style="color: #333333;">+</span> rainRate4 <span style="color: #333333;">+</span>\
battery <span style="color: #333333;">+</span> channel <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0x2</span> <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0x9</span> <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0x1</span> <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0x4</span>
<span style="color: #008800; font-weight: bold;">if</span> (((checksum <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">!=</span> messageChecksum1 <span style="color: black; font-weight: bold;">or</span> (checksum <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">!=</span> messageChecksum2):
<span style="color: #888888;">#// checksum error</span>
<span style="color: #008800; font-weight: bold;">return</span> <span style="background-color: #fff0f0;">""</span>
totRain <span style="color: #333333;">=</span> ((totRain1 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">100000</span>) <span style="color: #333333;">+</span> (totRain2 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">10000</span>) <span style="color: #333333;">+</span> (totRain3 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">1000</span>) <span style="color: #333333;">+</span>\
(totRain4 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">100</span>) <span style="color: #333333;">+</span> (totRain5 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">10</span>) <span style="color: #333333;">+</span> totRain6)<span style="color: #333333;">/</span><span style="color: #6600ee; font-weight: bold;">1000.0</span><span style="color: #333333;">*</span><span style="color: #6600ee; font-weight: bold;">25.4</span>
rainRate <span style="color: #333333;">=</span> ((rainRate1 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">1000</span>) <span style="color: #333333;">+</span> (rainRate2 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">100</span>) <span style="color: #333333;">+</span> (rainRate3 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">10</span>) <span style="color: #333333;">+</span> rainRate4)<span style="color: #333333;">/</span><span style="color: #6600ee; font-weight: bold;">100.0</span><span style="color: #333333;">*</span><span style="color: #6600ee; font-weight: bold;">25.4</span>
<span style="color: #888888;">#std::stringstream retString;</span>
<span style="color: #888888;">#retString << "class:sensor;protocol:oregon;model:2914;id:" << static_cast<int>(rollingcode)</span>
<span style="color: #888888;"># << ";raintotal:" << std::fixed << std::setprecision(1) << totRain</span>
<span style="color: #888888;"># << ";rainrate:" << std::fixed << std::setprecision(1) << rainRate << ";";</span>
<span style="color: #888888;">#return "%d\t%f\t%f"%(rollingcode, totRain, rainRate)</span>
<span style="color: #008800; font-weight: bold;">return</span> [rollingcode, totRain, rainRate, battery]
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">decode1994</span>(inp):
<span style="color: #888888;">#source:telldus-core/service/ProtocolOregon.cpp@c9567f</span>
<span style="color: #888888;">#wind</span>
value <span style="color: #333333;">=</span> <span style="color: #007020;">int</span>(inp, <span style="color: #0000dd; font-weight: bold;">16</span>)
crcCheck <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
messageChecksum1 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
messageChecksum2 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
avg1 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
avg2 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
avg3 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
gust1 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
gust2 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
gust3 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
unknown1 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
unknown2 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
direction <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
battery <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span> <span style="color: #888888;">#// PROBABLY battery</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
rollingcode <span style="color: #333333;">=</span> ((value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">+</span> (value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>)
checksum <span style="color: #333333;">=</span> ((value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">+</span> (value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>)
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">8</span>
channel <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
checksum <span style="color: #333333;">=</span> checksum <span style="color: #333333;">+</span> unknown1 <span style="color: #333333;">+</span> unknown2 <span style="color: #333333;">+</span> avg1 <span style="color: #333333;">+</span> avg2 <span style="color: #333333;">+</span> avg3 <span style="color: #333333;">+</span> gust1 <span style="color: #333333;">+</span> gust2 <span style="color: #333333;">+</span> gust3 <span style="color: #333333;">+</span> direction <span style="color: #333333;">+</span> battery <span style="color: #333333;">+</span> channel
checksum <span style="color: #333333;">=</span> checksum <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0x1</span> <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0x9</span> <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0x9</span> <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0x4</span>
<span style="color: #008800; font-weight: bold;">if</span> (((checksum <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">!=</span> messageChecksum1 <span style="color: black; font-weight: bold;">or</span> (checksum <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">!=</span> messageChecksum2):
<span style="color: #888888;">#// checksum error</span>
<span style="color: #008800; font-weight: bold;">return</span> <span style="background-color: #fff0f0;">""</span>
avg <span style="color: #333333;">=</span> ((avg1 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">100</span>) <span style="color: #333333;">+</span> (avg2 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">10</span>) <span style="color: #333333;">+</span> avg3)<span style="color: #333333;">/</span><span style="color: #6600ee; font-weight: bold;">10.0</span>
gust <span style="color: #333333;">=</span> ((gust1 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">100</span>) <span style="color: #333333;">+</span> (gust2 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">10</span>) <span style="color: #333333;">+</span> gust3)<span style="color: #333333;">/</span><span style="color: #6600ee; font-weight: bold;">10.0</span>
directiondegree <span style="color: #333333;">=</span> <span style="color: #6600ee; font-weight: bold;">22.5</span> <span style="color: #333333;">*</span> direction
<span style="color: #888888;">#retString << "class:sensor;protocol:oregon;model:1984;id:" << static_cast<int>(rollingcode)</span>
<span style="color: #888888;"># << ";winddirection:" << directiondegree</span>
<span style="color: #888888;"># << ";windaverage:" << std::fixed << std::setprecision(1) << avg</span>
<span style="color: #888888;"># << ";windgust:" << std::fixed << std::setprecision(1) << gust << ";";</span>
<span style="color: #888888;">#return '%d\t%f\t%f\t%f'%(rollingcode, avg, gust, directiondegree)</span>
<span style="color: #008800; font-weight: bold;">return</span> [rollingcode, avg, gust, directiondegree, battery]
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">decode1984</span>(inp):
<span style="color: #888888;">#source:telldus-core/service/ProtocolOregon.cpp@c9567f</span>
<span style="color: #888888;">#// wind</span>
value <span style="color: #333333;">=</span> <span style="color: #007020;">int</span>(inp, <span style="color: #0000dd; font-weight: bold;">16</span>)
crcCheck <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
messageChecksum1 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
messageChecksum2 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
avg1 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
avg2 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
avg3 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
gust1 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
gust2 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
gust3 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
unknown1 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
unknown2 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
direction <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
battery <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span> <span style="color: #888888;">#// PROBABLY battery</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
rollingcode <span style="color: #333333;">=</span> ((value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">+</span> (value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>)
checksum <span style="color: #333333;">=</span> ((value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">+</span> (value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>)
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">8</span>
channel <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
checksum <span style="color: #333333;">=</span> checksum <span style="color: #333333;">+</span> unknown1 <span style="color: #333333;">+</span> unknown2 <span style="color: #333333;">+</span> avg1 <span style="color: #333333;">+</span> avg2 <span style="color: #333333;">+</span> avg3 <span style="color: #333333;">+</span> gust1 <span style="color: #333333;">+</span> gust2 <span style="color: #333333;">+</span> gust3 <span style="color: #333333;">+</span> direction <span style="color: #333333;">+</span> battery <span style="color: #333333;">+</span> channel
checksum <span style="color: #333333;">=</span> checksum <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0x1</span> <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0x9</span> <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0x8</span> <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0x4</span>
<span style="color: #008800; font-weight: bold;">if</span> (((checksum <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">!=</span> messageChecksum1 <span style="color: black; font-weight: bold;">or</span> (checksum <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">!=</span> messageChecksum2):
<span style="color: #888888;">#// checksum error</span>
<span style="color: #008800; font-weight: bold;">return</span> <span style="background-color: #fff0f0;">""</span>
avg <span style="color: #333333;">=</span> ((avg1 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">100</span>) <span style="color: #333333;">+</span> (avg2 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">10</span>) <span style="color: #333333;">+</span> avg3)<span style="color: #333333;">/</span><span style="color: #6600ee; font-weight: bold;">10.0</span>
gust <span style="color: #333333;">=</span> ((gust1 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">100</span>) <span style="color: #333333;">+</span> (gust2 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">10</span>) <span style="color: #333333;">+</span> gust3)<span style="color: #333333;">/</span><span style="color: #6600ee; font-weight: bold;">10.0</span>
directiondegree <span style="color: #333333;">=</span> <span style="color: #6600ee; font-weight: bold;">22.5</span> <span style="color: #333333;">*</span> direction
<span style="color: #888888;">#retString << "class:sensor;protocol:oregon;model:1984;id:" << static_cast<int>(rollingcode)</span>
<span style="color: #888888;"># << ";winddirection:" << directiondegree</span>
<span style="color: #888888;"># << ";windaverage:" << std::fixed << std::setprecision(1) << avg</span>
<span style="color: #888888;"># << ";windgust:" << std::fixed << std::setprecision(1) << gust << ";";</span>
<span style="color: #888888;">#return '%d\t%f\t%f\t%f'%(rollingcode,avg, gust, directiondegree)</span>
<span style="color: #008800; font-weight: bold;">return</span> [rollingcode, avg, gust, directiondegree, battery]
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">decodeF824</span>(inp):
<span style="color: #888888;">#source:telldus-core/service/ProtocolOregon.cpp@c9567f</span>
value <span style="color: #333333;">=</span> <span style="color: #007020;">int</span>(inp, <span style="color: #0000dd; font-weight: bold;">16</span>)
crcCheck <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value<span style="color: #333333;">>></span><span style="color: #0000dd; font-weight: bold;">4</span>
messageChecksum1 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span><span style="color: #0000dd; font-weight: bold;">4</span>
messageChecksum2 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
unknown <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
hum1 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
hum2 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
neg <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
temp1 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
temp2 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
temp3 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
battery <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>
rollingcode <span style="color: #333333;">=</span> ((value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">+</span> (value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>)
checksum <span style="color: #333333;">=</span> ((value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">+</span> (value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>)
value <span style="color: #333333;">=</span> value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">8</span>
channel <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>
checksum <span style="color: #333333;">+=</span> unknown <span style="color: #333333;">+</span> hum1 <span style="color: #333333;">+</span> hum2 <span style="color: #333333;">+</span> neg <span style="color: #333333;">+</span> temp1 <span style="color: #333333;">+</span> temp2 <span style="color: #333333;">+</span> temp3 <span style="color: #333333;">+</span> battery <span style="color: #333333;">+</span> channel <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0xF</span> <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0x8</span> <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0x2</span> <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0x4</span>
<span style="color: #008800; font-weight: bold;">if</span> ((((checksum <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">!=</span> messageChecksum1) <span style="color: black; font-weight: bold;">or</span> ((checksum <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">!=</span> messageChecksum2)):
<span style="color: #008800; font-weight: bold;">return</span> <span style="background-color: #fff0f0;">""</span>
temperature <span style="color: #333333;">=</span> ((temp1 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">100</span>) <span style="color: #333333;">+</span> (temp2 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">10</span>) <span style="color: #333333;">+</span> temp3)<span style="color: #333333;">/</span><span style="color: #6600ee; font-weight: bold;">10.0</span>
<span style="color: #008800; font-weight: bold;">if</span> (neg):
temperature <span style="color: #333333;">=</span> <span style="color: #333333;">-</span>temperature
humidity <span style="color: #333333;">=</span> (hum1 <span style="color: #333333;">*</span> <span style="color: #6600ee; font-weight: bold;">10.0</span>) <span style="color: #333333;">+</span> hum2
<span style="color: #888888;">#retStr = "class:sensor;protocol:oregon;model:F824;id:" #14;temp:0.0;humidity:46;</span>
<span style="color: #888888;">#retStr = '%s%d;temp:%1.1f;humidity:%d;'%(retStr,rollingcode,temperature,humidity)</span>
<span style="color: #888888;">#return retStr</span>
<span style="color: #888888;">#return '%d\t%f\t%f'%(rollingcode, temperature, humidity)</span>
<span style="color: #008800; font-weight: bold;">return</span> [rollingcode, temperature, humidity, battery]
<span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">decode1A2D</span>(inp):
<span style="color: #888888;">#source:telldus-core/service/ProtocolOregon.cpp</span>
value <span style="color: #333333;">=</span> <span style="color: #007020;">int</span>(inp,<span style="color: #0000dd; font-weight: bold;">16</span>)
checksum2 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xFF</span>
value <span style="color: #333333;">=</span> value<span style="color: #333333;">>></span><span style="color: #0000dd; font-weight: bold;">8</span>
checksum1 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xFF</span>
value <span style="color: #333333;">=</span> value<span style="color: #333333;">>></span><span style="color: #0000dd; font-weight: bold;">8</span>
checksum <span style="color: #333333;">=</span> ((value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">+</span> (value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>)
hum1 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>;
value <span style="color: #333333;">>>=</span> <span style="color: #0000dd; font-weight: bold;">8</span>;
checksum <span style="color: #333333;">=</span> checksum <span style="color: #333333;">+</span> ((value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">+</span> (value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>)
neg <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> (<span style="color: #0000dd; font-weight: bold;">1</span> <span style="color: #333333;"><<</span> <span style="color: #0000dd; font-weight: bold;">3</span>)
hum2 <span style="color: #333333;">=</span> (value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>;
value <span style="color: #333333;">>>=</span> <span style="color: #0000dd; font-weight: bold;">8</span>
checksum <span style="color: #333333;">=</span> checksum <span style="color: #333333;">+</span> ((value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">+</span> (value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>);
temp2 <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>;
temp1 <span style="color: #333333;">=</span> (value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>;
value <span style="color: #333333;">>>=</span> <span style="color: #0000dd; font-weight: bold;">8</span>;
checksum <span style="color: #333333;">=</span> checksum <span style="color: #333333;">+</span> ((value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">+</span> (value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>)
temp3 <span style="color: #333333;">=</span> (value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>;
value <span style="color: #333333;">>>=</span> <span style="color: #0000dd; font-weight: bold;">8</span>
checksum <span style="color: #333333;">=</span> checksum <span style="color: #333333;">+</span> ((value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">+</span> (value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>)
rollingcode <span style="color: #333333;">=</span> value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xFF</span>;
value <span style="color: #333333;">>>=</span> <span style="color: #0000dd; font-weight: bold;">8</span>;
checksum <span style="color: #333333;">=</span> checksum <span style="color: #333333;">+</span> ((value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>) <span style="color: #333333;">+</span> (value <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0xF</span>)
channel <span style="color: #333333;">=</span> (value <span style="color: #333333;">>></span> <span style="color: #0000dd; font-weight: bold;">4</span>) <span style="color: #333333;">&</span> <span style="color: #005588; font-weight: bold;">0x7</span>;
battery <span style="color: #333333;">=</span> value<span style="color: #333333;">&</span><span style="color: #005588; font-weight: bold;">0xF</span> <span style="color: #888888;">#time will tell</span>
checksum <span style="color: #333333;">=</span> checksum <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0x1</span> <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0xA</span> <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0x2</span> <span style="color: #333333;">+</span> <span style="color: #005588; font-weight: bold;">0xD</span> <span style="color: #333333;">-</span> <span style="color: #005588; font-weight: bold;">0xA</span>;
<span style="color: #008800; font-weight: bold;">if</span> (checksum <span style="color: #333333;">!=</span> checksum1):
<span style="color: #008800; font-weight: bold;">return</span> <span style="background-color: #fff0f0;">"No"</span>;
temperature <span style="color: #333333;">=</span> ((temp1 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">100</span>) <span style="color: #333333;">+</span> (temp2 <span style="color: #333333;">*</span> <span style="color: #0000dd; font-weight: bold;">10</span>) <span style="color: #333333;">+</span> temp3)<span style="color: #333333;">/</span><span style="color: #6600ee; font-weight: bold;">10.0</span>;
<span style="color: #008800; font-weight: bold;">if</span> (neg): temperature <span style="color: #333333;">=</span> <span style="color: #333333;">-</span>temperature
humidity <span style="color: #333333;">=</span> (hum1 <span style="color: #333333;">*</span> <span style="color: #6600ee; font-weight: bold;">10.0</span>) <span style="color: #333333;">+</span> hum2
<span style="color: #888888;">#print "temp/hum ", temperature, "/", humidity</span>
<span style="color: #008800; font-weight: bold;">return</span> [rollingcode, temperature, humidity, battery]
</pre>
</div>
<br />dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com0tag:blogger.com,1999:blog-1082071635998277371.post-12970925076180130112018-09-30T23:46:00.003-07:002018-09-30T23:46:49.871-07:00VNC connections to ubuntu 18.04LTSAfter installing x11vnc there were the dreaded "unsupported security types" error message.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3jILqtn0STthj9RvPqlKhxpXPVvBpnxXSV4h9R3gMtPQSZqOqBv0vA44UxqdVuPptt0aZZPuAguFTC9-JtUof44s5S_XtaLs9zQPEB4sOCThgEJNJohvzx6KKmTG8DNxiCMaRJ1R1Ve0/s1600/realvncerror.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="291" data-original-width="740" height="125" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3jILqtn0STthj9RvPqlKhxpXPVvBpnxXSV4h9R3gMtPQSZqOqBv0vA44UxqdVuPptt0aZZPuAguFTC9-JtUof44s5S_XtaLs9zQPEB4sOCThgEJNJohvzx6KKmTG8DNxiCMaRJ1R1Ve0/s320/realvncerror.PNG" width="320" /></a></div>
<br />
I tried several things, including disabling the "wayland vnc server" in " /etc/gdm3/custom.conf".<br />
<br />
Nothing worked, in the end I just installed "lightdm" instead of the "gdm3". And after enabling screen sharing in the gui settings I had my vnc connection up and running again.<br />
<br />
<br />
<br />
<br />dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com0tag:blogger.com,1999:blog-1082071635998277371.post-87975549988128829672018-05-07T06:12:00.002-07:002019-05-29T06:58:03.951-07:00EdgeRouter X VPN connection to mullvad.netUPDATED <a href="https://dephiox.blogspot.com/2019/05/edgerouter-x-vpn-connection-to.html" target="_blank">here</a>. <br />
<br />
Backup your original settings by entering the gui interface, select the system tab in the lower part of the window and choose "Back Up Config" <br />
<br />
Copy these files that you obtained from mullvad.net to the edgeos router:<br />
<br />
<blockquote class="tr_bq">
ubnt@ubnt:~$ ls -l /config/auth/<br />
total 20<br />
-rw------- 1 root vyattacf 6296 May 7 13:38 mullvad_ca.crt<br />
-rw------- 1 ubnt vyattacf 2202 May 7 13:54 mullvad_crl.pem<br />
-rw------- 1 ubnt vyattacf 500 May 7 14:16 mullvad_no.conf<br />
-rw------- 1 ubnt vyattacf 19 May 7 14:09 mullvad_userpass.txt<br />
ubnt@ubnt:~$ </blockquote>
<br />
Here I am using the "mullvad_no.conf", but you should replace that with the location you are using.<br />
<br />
Edit the "mullvad_no.conf" file and insert "/config/auth" before all mullvad filenames (line 21-23 for me)<br />
<br />
<blockquote class="tr_bq">
auth-user-pass /config/auth/mullvad_userpass.txt<br />
ca /config/auth/mullvad_ca.crt<br />
crl-verify /config/auth/mullvad_crl.pem</blockquote>
<br />
Now, ***EDIT*** the following text to your settings:<br />
<blockquote class="tr_bq">
#openvpn to mullvad<br />
<br />
set interfaces openvpn vtun0 config-file <span style="color: blue;">/config/auth/mullvad_no.conf</span><br />
set interfaces openvpn vtun0 description 'Mullvad VPN'<br />
set interfaces openvpn vtun0 enable<br />
<br />
set service nat rule 5000 description MVPN<br />
set service nat rule 5000 log disable<br />
set service nat rule 5000 outbound-interface vtun0<br />
set service nat rule 5000 source address <span style="color: blue;"><span style="background-color: white;">10.0.0.0</span></span>/24 <br />
set service nat rule 5000 type masquerade<br />
<br />
set service nat rule 5001 description default<br />
set service nat rule 5001 log disable<br />
set service nat rule 5001 outbound-interface <span style="color: blue;">eth4</span><br />
set service nat rule 5001 source address <span style="background-color: white;"><span style="color: blue;">10.0.0.0</span></span>/24<br />
set service nat rule 5001 type masquerade<br />
<br />
set protocols static table 1 interface-route 0.0.0.0/0 next-hop-interface vtun0<br />
<br />
set firewall modify mullvad_route rule 10 description 'MVPN'<br />
set firewall modify mullvad_route rule 10 source address <span style="color: blue;">10.0.0.0</span>/24<br />
set firewall modify mullvad_route rule 10 modify table 1<br />
<br />
set interfaces switch switch0 firewall in modify mullvad_route</blockquote>
<br />
Changes would probably be in line 3,10,11,16 and 22, outlined in blue. My router are using 10.0.0.1 as the LAN address, eth4 connected to my ISP.<br />
<br />
On the edgeos router enter the command "configure" and paste the edited text into the terminal.<br />
<br />
Then enter the "commit" and "save" commands. Browse to your router web interface and refresh to observe the difference.<br />
<br />
And check the <a href="https://am.i.mullvad.net/" target="_blank">am.i.mullvad</a> link...<br />
<br />dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com0tag:blogger.com,1999:blog-1082071635998277371.post-10525043149695552482018-01-06T08:43:00.000-08:002018-01-06T08:43:48.783-08:00WAN IP address from Ubiquiti EdgeRouter ER-X<div class="tr_bq">
I got myself a new router, an Ubiquiti EdgeRouter ER-X , and when I tried to apply my old methods from the <a href="http://dephiox.blogspot.se/2016/01/obtaining-external-wan-ip-address-from.html" target="_blank">WNR2000v5</a> I discovered that the web pages returned were full of javascript. I could not find any WAN values in the files.</div>
<br />
And that was just as well, the edge router features a full OS, with python pre installed! I set it up with eth4 as the WAN port.<br />
<br />
The only caveat was the<br />
<br />
<blockquote class="tr_bq">
show interfaces ethernet eth4 brief</blockquote>
<br />
did not work in a script. The command<br />
<br />
<blockquote class="tr_bq">
/opt/vyatta/bin/vyatta-op-cmd-wrapper show interfaces ethernet eth4 brief</blockquote>
<br />
has to be used for it to work.<br />
<br />
So after setting it up to run via crontab with the command<br />
<br />
<blockquote class="tr_bq">
sudo -e crontab</blockquote>
the script were up and running.<br />
<br />
The working python script:<br />
<br />
<div>
<span style="font-size: x-small;">#!/usr/bin/python</span><br />
<span style="font-size: x-small;"><br /></span>
<span style="font-size: x-small;">import re, os, ftplib, pickle, StringIO</span><br />
<span style="font-size: x-small;"><br /></span>
<span style="font-size: x-small;">def touch(fname, times=None):</span><br />
<span style="font-size: x-small;"> with open(fname, 'a'):</span><br />
<span style="font-size: x-small;"> os.utime(fname, times)</span><br />
<span style="font-size: x-small;"><br /></span>
<span style="font-size: x-small;">cmd_path = '/opt/vyatta/bin/vyatta-op-cmd-wrapper'</span><br />
<span style="font-size: x-small;">cmd_res = os.popen(cmd_path+ ' show interfaces ethernet eth4 brief')</span><br />
<span style="font-size: x-small;">data = cmd_res.read()</span><br />
<span style="font-size: x-small;">cmd_res.close()</span><br />
<span style="font-size: x-small;"><br /></span>
<span style="font-size: x-small;"># Edgeos show interface command returns</span><br />
<span style="font-size: x-small;"># eth4 xxx.xxx.xxx.xxx</span><br />
<span style="font-size: x-small;">p = re.compile('eth4(\s*)(\d*).(\d*).(\d*).(\d*)')</span><br />
<span style="font-size: x-small;">m = p.search(data)</span><br />
<span style="font-size: x-small;"><br /></span>
<span style="font-size: x-small;">#m.groups()[0] is white space</span><br />
<span style="font-size: x-small;">if (m and len(m.groups()) == 5):</span><br />
<span style="font-size: x-small;"> current_ip = (m.groups()[1], m.groups()[2], m.groups()[3], m.groups()[4])</span><br />
<span style="font-size: x-small;"> try:</span><br />
<span style="font-size: x-small;"> last_ip = pickle.load(open('/home/user/myip/lastip', "rb" ))</span><br />
<span style="font-size: x-small;"> except IOError:</span><br />
<span style="font-size: x-small;"> last_ip = (1,2,3,4)</span><br />
<span style="font-size: x-small;"><br /></span>
<span style="font-size: x-small;"> if current_ip != last_ip:</span><br />
<span style="font-size: x-small;"> pickle.dump(current_ip,open('/home/user/myip/lastip', "wb" ))</span><br />
<span style="font-size: x-small;"> data ='<html><head><title>My IP</title></head><b>My IP:\</span><br />
<span style="font-size: x-small;">%d//%d//%d//%d</b></font></p></body></html>\</span><br />
<span style="font-size: x-small;">'%(int(m.groups()[1]),int(m.groups()[2]),int(m.groups()[3]),int(m.groups()[4]))</span><br />
<span style="font-size: x-small;"> output = StringIO.StringIO(data)</span><br />
<span style="font-size: x-small;"> ftp = ftplib.FTP('ftp.server.org', 'username','password')</span><br />
<span style="font-size: x-small;"> ftp.cwd('pub')</span><br />
<span style="font-size: x-small;"> ftp.storlines('STOR index.html', output)</span><br />
<span style="font-size: x-small;"> ftp.close()</span><br />
<span style="font-size: x-small;"> else:</span><br />
<span style="font-size: x-small;"> touch('/home/user/myip/lastip')</span></div>
dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com0tag:blogger.com,1999:blog-1082071635998277371.post-75881527125324486552017-09-18T00:50:00.000-07:002017-09-18T00:50:49.442-07:00Setup realvnc server on raspberry headless using tightvncviewerWhen I tried to connect to my headless raspberry via tightvncviewer I got the following message:<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZ_xkz1BSMMWIABQEcVPOKgMgyts50ZHJ3bP2aniDXQhAtR4ftFskHI30GW6h3VOl9OANPKB7y1xFftkR44FrJCKrYNnPfJN8uV26FkDIDnNb9oAjF5yGXrWQ4LZykj9OBh7y2RzNaBBU/s1600/realvncerror.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="291" data-original-width="740" height="156" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZ_xkz1BSMMWIABQEcVPOKgMgyts50ZHJ3bP2aniDXQhAtR4ftFskHI30GW6h3VOl9OANPKB7y1xFftkR44FrJCKrYNnPfJN8uV26FkDIDnNb9oAjF5yGXrWQ4LZykj9OBh7y2RzNaBBU/s400/realvncerror.PNG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<br /><br />It appears that you have to install a viewer from realvnc ($? or registration?) in order to connect.<div>
<br /></div>
<div>
<br /></div>
<div>
So I logged in to the raspberry via ssh and started a virtual vnc screen:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6mql-nNGUTbLfIwL3KwhyQYK0tyyp-vNDtWvTTQedinKq1XhDwoiBVsFXJIeN6XKyrxW2PzwB7tgeyws-b418DhfVenQsdC7j0U3jmt_N6WFrELCBiYrIdByeZkJvYdcV3ctV2MHSmT8/s1600/startingvirtualvnc.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="604" data-original-width="1030" height="372" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6mql-nNGUTbLfIwL3KwhyQYK0tyyp-vNDtWvTTQedinKq1XhDwoiBVsFXJIeN6XKyrxW2PzwB7tgeyws-b418DhfVenQsdC7j0U3jmt_N6WFrELCBiYrIdByeZkJvYdcV3ctV2MHSmT8/s640/startingvirtualvnc.PNG" width="640" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<blockquote class="tr_bq">
vncserver-virtual -Encryption PreferOn -Authentication VncAuth</blockquote>
<div>
This starts a new, virtual vnc server with the standard vnc authentications, tightvncviewer can connect to this one.</div>
<div>
<br /></div>
<div>
From this vnc connection I started a realvncviewer session to "localhost"</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ07GIIrYIMEEkTbBYsuUhdjm0qJc0WxbSc650vEKFCCUMN2UhGof954VgAUfpGT3amQNkXD_XKYwwAZQ04i530po0bT-aZepCwuGeF5wTXL1Uag2SfjubGSvpux_lEWm4JTB4M_EOCz8/s1600/startingrealvncviewer.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="459" data-original-width="727" height="202" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ07GIIrYIMEEkTbBYsuUhdjm0qJc0WxbSc650vEKFCCUMN2UhGof954VgAUfpGT3amQNkXD_XKYwwAZQ04i530po0bT-aZepCwuGeF5wTXL1Uag2SfjubGSvpux_lEWm4JTB4M_EOCz8/s320/startingrealvncviewer.PNG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Allowing me to change the options for the default vnc server connected to the "screen" (port 5900 or :0) on the raspberry.<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhg7BgPMdglIEUnbc0NB4NZ2nlh31AggQlUMGjqHGpnM2a4n1LYu8bGwybTGVuRb7v298nYDCNDbpQrgnUf0Y67jxw7E4G9Uw4w119366NKEE4xhi7Rf90BGIFn6JIMsra7QV4RiWjSTkA/s1600/vncinvnc.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1253" data-original-width="1559" height="514" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhg7BgPMdglIEUnbc0NB4NZ2nlh31AggQlUMGjqHGpnM2a4n1LYu8bGwybTGVuRb7v298nYDCNDbpQrgnUf0Y67jxw7E4G9Uw4w119366NKEE4xhi7Rf90BGIFn6JIMsra7QV4RiWjSTkA/s640/vncinvnc.PNG" width="640" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Accessing the options on the :0 realvnc server via realvnc viewer from a virtual (:1) realvncviewer from tightvncviewer.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
From the options change Security/Authentication from "UNIX password" to "VNC password".</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLn43njRPg3d_y9S0oUITmdLYQMtBH_B50LroKQTV_CTYmpLgyGGzm9YJ3kJfU1dP6HILsM3ynsAW5y2GOsNlrDlTrA_rvaHhUB5nGh98n2WIlh3VJGhWnEDBKuVZsq_DkEZEjIyCUhBY/s1600/realvncoptions.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="309" data-original-width="627" height="196" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLn43njRPg3d_y9S0oUITmdLYQMtBH_B50LroKQTV_CTYmpLgyGGzm9YJ3kJfU1dP6HILsM3ynsAW5y2GOsNlrDlTrA_rvaHhUB5nGh98n2WIlh3VJGhWnEDBKuVZsq_DkEZEjIyCUhBY/s400/realvncoptions.PNG" width="400" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Now it is possible to connect directly to the realvncserver from tightvncviewer.</div>
<div>
<br /></div>
<div>
<br /><div>
<br /></div>
<div>
<br /></div>
</div>
dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com0tag:blogger.com,1999:blog-1082071635998277371.post-54451085758452675052017-01-12T03:53:00.001-08:002017-01-12T04:07:43.837-08:00Fast forwarding the std::next_permutation algorithm<div class="tr_bq">
I started my computer with a project that looks more and more like Sisyfos work.</div>
<br />
It is trying to solve a puzzle by running through a set of permutations, and it is using std::next_permutation.<br />
<br />
However, a day into the computation I realized that the algorithm could be further improved. Should I stop the calculation and restart it? Or let it continue, with the ineffective algorithm?<br />
<br />
Looking at the internet I found an in depth explanation of <a href="http://stackoverflow.com/questions/11483060/stdnext-permutation-implementation-explanation" target="_blank">std::next_permutation Implementation Explanation</a>. std::next_permutation will from a starting point increase the permutation in an lexical fashion until it rolls over and returns false:<br />
<br />
<code>std::vector<int> skip_next_list = { 1,2,3,4, 5, 6, 7, 8, 9, 10, 11};</code><br />
<code>do {</code><br />
<code>//some work here</code><br />
<code>} while (std::next_permutation(skip_next_list.begin(), </code><span style="font-family: monospace;">skip_next_list.end())</span>);<br />
<br />
<br />
My search had reached 309000000 when I aborted the job, so I needed to fast forward to that point. I realized that for 6 iterations (3!) it would update the last three entries of skip_next_list, for 24 (4!) the last four and so on.<br />
<br />
So this is the skip_next_permutation function, fast forwarding to a number far into the sequence of std::next_permutation.<br />
<br />
<pre><span class="keyword">template</span><span class="operator"><</span><span class="keyword">typename</span> It<span class="operator">></span><span class="type"> void</span> skip_next_permutation<span class="operator">(</span>uint64_t skip_num<span class="operator">,</span> It begin<span class="operator">,</span> It end<span class="operator">)
{</span><span class="flow">
if</span><span class="operator"> (</span>skip_num<span class="operator"> <=</span><span class="int"> 0</span><span class="operator">)</span><span class="flow"> return</span><span class="operator">;</span><span class="comment"> // does not have to be an error
//build a lut of factorials, this could be a static
</span> std<span class="operator">::</span>vector<span class="operator"><</span>uint64_t<span class="operator">></span> factorials<span class="operator">;</span>
factorials<span class="operator">.</span>push_back<span class="operator">(</span><span class="int">1</span><span class="operator">);</span><span class="comment"> /// 0! == 1
</span><span class="type"> long</span> idx<span class="operator"> =</span><span class="int"> 1</span><span class="operator">;</span><span class="type">
long</span> input_length<span class="operator"> =</span> end<span class="operator"> -</span> begin<span class="operator">;</span><span class="flow">
do</span><span class="operator"> {</span>
factorials<span class="operator">.</span>push_back<span class="operator">(</span>factorials<span class="operator">[</span>idx<span class="operator">-</span><span class="int">1</span><span class="operator">] *</span> idx<span class="operator">);
}</span><span class="flow"> while</span><span class="operator"> (</span>factorials<span class="operator">[++</span>idx<span class="operator"> -</span><span class="int"> 1</span><span class="operator">] <=</span> skip_num<span class="operator">);</span><span class="comment"> //
// now start to loop, find the factorial that is one smaller than the number</span> we want to skip forward</pre>
<pre><span class="type"> long</span> my_inc<span class="operator"> =</span> factorials<span class="operator">.</span>size<span class="operator">() -</span><span class="int"> 2</span><span class="operator">;</span><span class="comment"> // always 2 lower than factorials.size()
</span><span class="flow">
do</span><span class="operator">
{</span><span class="type">
int</span> quotient<span class="operator"> =</span> skip_num<span class="operator"> /</span> factorials<span class="operator">[</span>my_inc<span class="operator">];</span>
skip_num<span class="operator"> =</span> skip_num<span class="operator">%</span>factorials<span class="operator">[</span>my_inc<span class="operator">];</span><span class="comment"> //the remaider are the remaining skip_num
</span><span class="flow">
if</span><span class="operator"> (</span>skip_num<span class="operator"> ==</span><span class="int"> 0</span><span class="operator"> &&</span> quotient<span class="operator"> ==</span><span class="int"> 0</span><span class="operator">)</span><span class="flow"> goto</span> end_loop<span class="operator">;</span>
std<span class="operator">::</span>swap<span class="operator">(</span>begin<span class="operator">[</span>input_length<span class="operator"> -</span> my_inc<span class="operator"> -</span><span class="int"> 1</span><span class="operator">],</span> begin<span class="operator">[</span>input_length<span class="operator"> -</span> my_inc<span class="operator"> +</span> quotient<span class="operator"> -</span><span class="int"> 1</span><span class="operator">]);</span>
std<span class="operator">::</span>sort<span class="operator">(</span>begin<span class="operator"> +</span> input_length<span class="operator"> -</span> my_inc<span class="operator">,</span> end<span class="operator">);</span><span class="comment"> //avoid with clever management?
</span> my_inc<span class="operator">--;
}</span><span class="flow"> while</span><span class="operator"> (</span>my_inc<span class="operator"> >=</span><span class="int"> 1</span><span class="operator">);</span>
end_loop<span class="operator">:</span><span class="flow">
return</span><span class="operator">;
}</span></pre>
The following table shows the factorials std::next_permutation algorithm exhausted, the number used for skip_next_permutation and the time std::next_permutation used.<br />
<br />
<div align="right">
</div>
<br />
<table>
<tbody>
<tr>
<th><div align="center">
Factorial</div>
</th>
<th><div align="center">
Number</div>
</th>
<th><div align="center">
Time / ms</div>
</th>
</tr>
<tr>
<td><div align="right">
9!</div>
</td>
<td><div align="right">
362 879</div>
</td>
<td><div align="right">
0.9</div>
</td>
</tr>
<tr>
<td><div align="right">
12!</div>
</td>
<td><div align="right">
39 916 799</div>
</td>
<td><div align="right">
94.1</div>
</td>
</tr>
<tr>
<td><div align="right">
13!</div>
</td>
<td><div align="right">
6 227 020 799</div>
</td>
<td><div align="right">
14 436.6</div>
</td>
</tr>
</tbody></table>
<br />
<br />
The fast forward function skip_next_permutation uses approximately 0.009 ms for all the values.dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com0tag:blogger.com,1999:blog-1082071635998277371.post-25223147071404660562016-11-28T04:16:00.000-08:002016-11-28T04:16:12.932-08:00More sensors for Tellstick local access<div class="tr_bq">
After obtaining local network access to the <a href="http://dephiox.blogspot.se/2016/11/local-access-to-tellstick-net-via-python.html" target="_blank">Tellstick net</a> I also have a wind sensor and a rain sensor close to my Tellstick net. Again, translating the Telldus .cpp code to python, the following python code gives the same results as the Telldus Live page. The code for the 1984/1994 sensors are identical except for the:</div>
<blockquote class="tr_bq">
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">checksum = checksum + 0x1 + 0x9 + 0x8 + 0x4</span></blockquote>
<div class="tr_bq">
<span style="font-family: inherit;">vs</span></div>
<blockquote class="tr_bq">
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">checksum = checksum + 0x1 + 0x9 + 0x9 + 0x4</span></blockquote>
checksum calculation. Here are the python code.<br />
<blockquote>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">def decode2914(inp):<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#source:telldus-core/service/ProtocolOregon.cpp@c9567f<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#// rain<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = int(inp, 16)<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>messageChecksum1 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>messageChecksum2 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>totRain1 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>totRain2 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>totRain3 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>totRain4 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>totRain5 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>totRain6 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>rainRate1 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>rainRate2 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>rainRate3 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>rainRate4 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>battery = value & 0xF<span class="Apple-tab-span" style="white-space: pre;"> </span>#// PROBABLY battery<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>rollingcode = ((value >> 4) & 0xF) + (value & 0xF)<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>checksum = ((value >> 4) & 0xF) + (value & 0xF)<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 8<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>channel = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>checksum = checksum + totRain1 + totRain2 + totRain3 + totRain4 + totRain5 + totRain6 +\<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>rainRate1 + rainRate2 + rainRate3 + rainRate4 +\<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>battery + channel + 0x2 + 0x9 + 0x1 + 0x4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>if (((checksum >> 4) & 0xF) != messageChecksum1 or (checksum & 0xF) != messageChecksum2):<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#// checksum error<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>return ""<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>totRain = ((totRain1 * 100000) + (totRain2 * 10000) + (totRain3 * 1000) +\<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>(totRain4 * 100) + (totRain5 * 10) + totRain6)/1000.0*25.4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>rainRate = ((rainRate1 * 1000) + (rainRate2 * 100) + (rainRate3 * 10) + rainRate4)/100.0*25.4<br /><br /><span class="Apple-tab-span" style="white-space: pre;"> </span>return "%f\t%f"%(totRain, rainRate)<br /><br /><br /><br />def decode1994(inp):<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#source:telldus-core/service/ProtocolOregon.cpp@c9567f<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#wind<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = int(inp, 16)<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>crcCheck = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>messageChecksum1 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>messageChecksum2 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>avg1 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>avg2 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>avg3 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>gust1 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>gust2 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>gust3 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>unknown1 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>unknown2 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>direction = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>battery = value & 0xF #// PROBABLY battery<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>rollingcode = ((value >> 4) & 0xF) + (value & 0xF)<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>checksum = ((value >> 4) & 0xF) + (value & 0xF)<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 8<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>channel = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>checksum = checksum + unknown1 + unknown2 + avg1 + avg2 + avg3 + gust1 + gust2 + gust3 + direction + battery + channel<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>checksum = checksum + 0x1 + 0x9 + 0x9 + 0x4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>if (((checksum >> 4) & 0xF) != messageChecksum1 or (checksum & 0xF) != messageChecksum2):<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#// checksum error<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>return ""<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>avg = ((avg1 * 100) + (avg2 * 10) + avg3)/10.0<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>gust = ((gust1 * 100) + (gust2 * 10) + gust3)/10.0<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>directiondegree = 22.5 * direction<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>return '%f\t%f\t%f'%(avg, gust, directiondegree)<br /></span></blockquote>
<br />
<blockquote>
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">def decode1984(inp):<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#source:telldus-core/service/ProtocolOregon.cpp@c9567f<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#// wind<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = int(inp, 16)<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>crcCheck = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>messageChecksum1 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>messageChecksum2 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>avg1 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>avg2 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>avg3 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>gust1 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>gust2 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>gust3 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>unknown1 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>unknown2 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>direction = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>battery = value & 0xF #// PROBABLY battery<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>rollingcode = ((value >> 4) & 0xF) + (value & 0xF)<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>checksum = ((value >> 4) & 0xF) + (value & 0xF)<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 8<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>channel = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>checksum = checksum + unknown1 + unknown2 + avg1 + avg2 + avg3 + gust1 + gust2 + gust3 + direction + battery + channel<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>checksum = checksum + 0x1 + 0x9 + 0x8 + 0x4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>if (((checksum >> 4) & 0xF) != messageChecksum1 or (checksum & 0xF) != messageChecksum2):<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#// checksum error<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>return ""<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>avg = ((avg1 * 100) + (avg2 * 10) + avg3)/10.0<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>gust = ((gust1 * 100) + (gust2 * 10) + gust3)/10.0<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>directiondegree = 22.5 * direction<br /><br /><span class="Apple-tab-span" style="white-space: pre;"> </span>return '%f\t%f\t%f'%(avg, gust, directiondegree)</span></blockquote>
<div>
Just add some more checks in the while loop</div>
<div>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">while 1:<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>try:<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>data,(address, port) = sock.recvfrom(1040)<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#print data<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>if (data.split(":")[6][6:10]=="F824"):<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#print data.split(":")[7][5:5+14]<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>print decodeF824(data.split(":")[7][5:5+14])<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>elif (data.split(":")[6][6:10]=="1984"):<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#print data.split(":")[7][5:5+16]<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>print decode1984(data.split(":")[7][5:5+16])<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>elif (data.split(":")[6][6:10]=="2914"):<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#print data.split(":")[7][5:5+16]<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>print decode2914(data.split(":")[7][5:5+16])<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>else:<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>print data<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#fp.write(data + '\n');<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#fp.flush()<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>except KeyboardInterrupt:<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>print "done"<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#fp.close()<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>break<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>except: # time out, try again<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>pass</span></blockquote>
</div>
<div>
<br /></div>
<div>
<br /></div>
dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com2tag:blogger.com,1999:blog-1082071635998277371.post-13874880249474329072016-11-25T02:56:00.000-08:002018-10-09T04:00:28.400-07:00Local access to Tellstick net via pythonI installed a Tellstick net and were pretty baffled that there were no obvious way to access the thing locally. At least according to my internet search.<br />
<div>
<br /></div>
<div>
<a href="http://telldus.se/" target="_blank">Telldus</a> are providing source codes for free, the only problem seems to be how the information is arranged.</div>
<div>
<br /></div>
<div>
By piecing together information found various places I came up with the following:</div>
<div>
<br /></div>
<div>
Send an udp message on port 30303, all Tellstick net devices on the local network will respond to this with a string containing some unit specific information AND the IP address on the network.</div>
<div>
<br /></div>
<div>
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">sock.sendto(DISCOVERY_PAYLOAD, (DISCOVERY_ADDRESS, DISCOVERY_PORT))</span><br style="font-family: "Courier New", Courier, monospace;" /><span style="font-family: "courier new" , "courier" , monospace;">data, (address, port) = sock.recvfrom(1024)</span></span></div>
<div>
<br /></div>
<div>
Then send a command that will make the Tellstick net echo the sensor information back via upd:</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">sock.sendto("B:reglistener", (address, 42314))</span> #I really love those port numbers</div>
<div>
<br /></div>
<div>
Read the upd port and filter for the sensors you want. This is how a Oregon model F824 output could look like:</div>
<div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">7:RawDatah5:class6:sensor8:protocol6:oregon5:modeliF824s4:datai20E1730096074Ass</span></div>
</div>
<div>
<br /></div>
<div>
There are a lot regarding decoding Oregon data on the internet, I translated the telldus-core .cpp to python.</div>
<div>
<br /></div>
<div>
And it works, sometimes the output can be .1C or 1% humidity off compared to my Oregon display. The values match the values from Telldus Live though.</div>
<blockquote>
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: xx-small;">import socket<br />from datetime import timedelta<br />import time<br />def decodeF824(inp):<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#source:telldus-core/service/ProtocolOregon.cpp@c9567f<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = int(inp, 16)<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>crcCheck = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value>>4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>messageChecksum1 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >>4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>messageChecksum2 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>unknown = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>hum1 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>hum2 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>neg = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>temp1 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>temp2 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>temp3 = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>battery = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>rollingcode = ((value >> 4) & 0xF) + (value & 0xF)<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>checksum = ((value >> 4) & 0xF) + (value & 0xF)<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>value = value >> 8<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>channel = value & 0xF<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>checksum += unknown + hum1 + hum2 + neg + temp1 + temp2 + temp3 + battery + channel + 0xF + 0x8 + 0x2 + 0x4<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>if ((((checksum >> 4) & 0xF) != messageChecksum1) or ((checksum & 0xF) != messageChecksum2)):<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>return ""<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>temperature = ((temp1 * 100) + (temp2 * 10) + temp3)/10.0<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>if (neg):<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>temperature = -temperature<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>humidity = (hum1 * 10.0) + hum2<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>retStr = "class:sensor;protocol:oregon;model:F824;id:" #14;temp:0.0;humidity:46;<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>retStr = '%s%d;temp:%1.1f;humidity:%d;'%(retStr,rollingcode,temperature,humidity)<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>return retStr<br /><br /><br />DISCOVERY_PORT = 30303<br />DISCOVERY_ADDRESS = '<broadcast>'<br />DISCOVERY_PAYLOAD = b"D"<br />DISCOVERY_TIMEOUT = timedelta(seconds=5)<br />sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)<br />sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)<br />sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)<br />sock.settimeout(DISCOVERY_TIMEOUT.seconds)<br />sock.sendto(DISCOVERY_PAYLOAD, (DISCOVERY_ADDRESS, DISCOVERY_PORT))<br />data, (address, port) = sock.recvfrom(1024)<br />print data, address, port<br />time.sleep(1)<br />#fp = open("tellstick.data", "w")<br />print "listening..."<br />#UDPSock.sendto("A:disconnect", (address,42314)) #will reboot the Tellstick net<br />sock.sendto("B:reglistener", (address, 42314))<br />while 1:<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>try:<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>data,(address, port) = sock.recvfrom(10240)<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>print data<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>if (data.split(":")[6][6:10]=="F824"):<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>print decodeF824(data.split(":")[7][5:5+14])<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#fp.write(data + '\n');<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#fp.flush()<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>except KeyboardInterrupt:<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>print "done"<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>#fp.close()<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>break<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>except: # time out, try again<br /><span class="Apple-tab-span" style="white-space: pre;"> </span>pass</span></blockquote>
<div>
<br /></div>
dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com0tag:blogger.com,1999:blog-1082071635998277371.post-10972478882125620742016-10-12T01:22:00.005-07:002016-10-12T02:56:16.284-07:00A license system using Crypto++ with RSA keysIf someone really wants to hack your software they can. Sony tried to make copying impossible and ended up in <a href="https://en.wikipedia.org/wiki/Sony_BMG_copy_protection_rootkit_scandal" target="_blank">court</a>. My take is the same as when I lock my bike. It is not difficult to take the bike but you have to make a thief of yourself in order to do it.<br />
<br />
Crypto++ is found <a href="https://www.cryptopp.com/" target="_blank">here</a>.<br />
<div>
<br /></div>
<div>
<span style="font-family: "helvetica neue" , "arial" , "helvetica" , sans-serif; font-size: small;">Step one</span> in this process is to obtain some specifics regarding the hardware of the PC running your software. Serial numbers from hard drives, volume serial numbers, amount/speed of RAM. Anything can be used, note also the possible hassle your paying customers will suffer if they do anything to their PC at a later stage.</div>
<div>
<br /></div>
<div>
Hash this number, for Crypto++ this could be done something like this:<br />
<br /></div>
<pre><span style="color: red; font-family: "courier new" , "courier" , monospace; font-size: x-small;">std::string SHA256HashString(std::string aString) {
std::string digest;
CryptoPP::SHA256 hash;
CryptoPP::StringSource foo(aString, true,
new CryptoPP::HashFilter(hash,
new CryptoPP::HexEncoder(
new CryptoPP::StringSink(digest))));
return digest;
}</span>
</pre>
Make your customer send you this number. It is not feasible to recreate their hardware ID from this hash.<br />
<br />
<br />
<div>
<span style="font-family: "helvetica neue" , "arial" , "helvetica" , sans-serif;">Step two</span> is preparing your private and public keys.<br />
<pre><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span style="color: red;">
AutoSeededRandomPool rng;
...
RSA::PrivateKey rsa_private;
rsa_private.GenerateRandomWithKeySize(rng, 512); //select your keysize here
bool isok = rsa_private.Validate(rng, 3);//Always check certificates your
//program reads from external sources
ByteQueue private_queue;
rsa_private.Save(private_queue);
FileSink private_file_sink("private.bin");
private_queue.CopyTo(private_file_sink);
private_file_sink.MessageEnd();
</span></span></pre>
Just save the private key as a binary, nobody will look into this file, you could choose to do the same with the public key. I chose to hard code this file into my application, so I will save it as a base64 encoded string.</div>
<pre><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">
<span style="color: red;">RSA::PublicKey rsa_public(rsa_private);
isok = rsa_public.Validate(rng, 3);
ByteQueue public_queue;
rsa_public.Save(public_queue);
string ss_base64;
Base64Encoder base64encoder_sink(new StringSink(ss_base64));
public_queue.CopyTo(base64encoder_sink);
base64encoder_sink.MessageEnd();
cout << ss_base64 << endl;
ofstream file_b64("public.b64");
file_b64 << ss_base64;
file_b64.close();
</span></span></pre>
<br />
<span style="font-family: "helvetica neue" , "arial" , "helvetica" , sans-serif;">Step three</span> is signing a file containing the information from step one. For me this a line containing the customers name and a line containing the hardware id hash.<br />
<br />
<pre><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span style="color: red;"> RSASSA_PKCS1v15_SHA_Signer signer(rsa_private);
// Create signature space
size_t length = signer.MaxSignatureLength();
SecByteBlock signature(length);
// Sign message
length = signer.SignMessage(rng, (const byte*)message.c_str(),
message.length(), signature);
// Resize now we know the true size of the signature
signature.resize(length);
string sig_string((char*)signature.data(), signature.size());
Base64Encoder encoder;
encoder.Put((byte*)sig_string.c_str(), sig_string.size());
encoder.MessageEnd();
word64 size = encoder.MaxRetrievable();
string encoded;
if (size)
{
encoded.resize(size);
encoder.Get((byte*)encoded.data(), encoded.size());
}
cout << encoded << endl;
ofstream file_b642("signature.b64");
file_b642 << encoded;
file_b642.close();
</span></span></pre>
<br />
In order to keep everything in one file I now append the base 64 signature to the customer information.<br />
<br />
<pre><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span style="color: red;">
Customer name, place
hardware id hash
----
mflkdhjgs6fdli9456fjgdklSDGty5ftgd
MDSWFrt+wegGgGmorebase64charshere
</span></span></pre>
<br />
I will call this file "license.txt" and send it to the customer.<br />
<br />
<span style="font-family: "helvetica neue" , "arial" , "helvetica" , sans-serif;">Step four</span>. My application reads the hardware info, hashes it and compares it with the hash in the license.txt file. If it matches I will verify the hash with the signature. This way I know the hardware hash is not just copied.<br />
A routine to decode base 64:<br />
<pre><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span style="color: red;">
string b64_decoder(string b64_str)
{
Base64Decoder b64_decoder;
b64_decoder.Put((byte*)b64_str.data(), b64_str.size());
b64_decoder.MessageEnd();
string decoded_str;
word64 size = b64_decoder.MaxRetrievable();
if (size && size <= SIZE_MAX)
{
decoded_str.resize(size);
b64_decoder.Get((byte*)decoded_str.data(), decoded_str.size());
}
else
{
decoded_str = "";
}
return decoded_str;
}
</span></span></pre>
<span style="font-family: "helvetica neue" , "arial" , "helvetica" , sans-serif;">Step five</span> recreates the public certificate, creates a verifier and checks the message vs the signature. Begin by debase64 both the public key and the signature:
<br />
<pre><span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><span style="color: red;">
size_t pos = license_txt.find("----", 0); //Check your findings...
string message_txt = trim(license_txt.substr(0, pos));
string signature = b64_decoder(trim(license_txt.substr(pos + 4)));
string public_b64 = "hm+560dXdR4dmorebase64charshere"
//rsa_public
string rsa_public_str = b64_decoder(public_b64);
RSA::PublicKey rsa_public;
StringSource stringSource(rsa_public_str, true);
rsa_public.BERDecode(stringSource);
if (!rsa_public.Validate(rng, 3))
{
//if this is wrong someone has actually tampered with the code
}
// Verifier object
RSASSA_PKCS1v15_SHA_Verifier verifier(rsa_public);
// Verify
bool result = verifier.VerifyMessage((const byte*)message_txt.c_str(),
message_txt.length(), (const byte*)signature.data(), signature.size());
// Result
if (true == result) {
cout << "All OK" << endl;
}
else {
cout << "bah bah baaaaa" << endl;
}
</span></span></pre>
Well, this is my implemetion at least.
dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com0tag:blogger.com,1999:blog-1082071635998277371.post-77480742476042892762016-01-22T00:39:00.000-08:002016-01-22T01:08:16.953-08:00Obtaining the external WAN IP address from a Netgear WNR2000v5Earlier I used a DNS service in order to get the IP address of my internet connection. I used some free ones, and they worked very well. Until they didn't work.<br />
<div>
<br /></div>
<div>
Then I used an external server, like duckduckgo.com, utilizing the computer, with python, already running in my house. Something like:</div>
<div>
<br /></div>
<div>
<pre>adr = "https://duckduckgo.com/?q=what+is+my+ip&ia=answer"
req = urllib2.Request(adr)
res = urllib2.urlopen(req)
data = res.read()
res.close()
...
p = re.compile('\"Answer\":"Your IP address is (\d*).(\d*).(\d*).(\d*) in')
m = p.search(data)
...
current_ip = (m.groups()[0], m.groups()[1], m.groups()[2], m.groups()[3])
...
</pre>
<br />
This data were then uploaded to a know web page if it were different from the previous address.<br />
<br />
And that worked great, until I occasionally started to use a VPN service on the machine running the script. Then duckduckgo.com returned the IP address of my VPN, which would not forward my ssh logins to my home.<br />
<br />
<br />
So I checked my router, Netgear WNR2000v5, and it returned the IP address as expected. But only from the page "RST_conn_status.htm". It would also return "Access denied" for the first login attempt if someone had logged in to the router for another machine. And it required a username/password.<br />
<br />
The script then became:<br />
<br /></div>
<pre>username='admin'
password='password'
adr = 'http://10.0.0.1/RST_conn_status.htm'
try: #if someone else logged in to the router we get access denied the first time
req = urllib2.Request(adr)
base64string = base64.encodestring('%s:%s'%(username, password)).replace('\n', '')
req.add_header("Authorization", "Basic %s" % base64string)
res = urllib2.urlopen(req)
except:
time.sleep(1)</pre>
<pre>req = urllib2.Request(adr)
base64string = base64.encodestring('%s:%s' % (username, password)).replace('\n', '')
req.add_header("Authorization", "Basic %s" % base64string)
res = urllib2.urlopen(req)
time.sleep(1)
data = res.read()
res.close()
...
p = re.compile('var info_get_wanip=\"(\d*).(\d*).(\d*).(\d*)\";')
m = p.search(data)
...
current_ip = (m.groups()[0], m.groups()[1], m.groups()[2], m.groups()[3])
...
</pre>
<pre></pre>
<br />dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com1tag:blogger.com,1999:blog-1082071635998277371.post-23165154369872135992014-10-04T22:50:00.003-07:002014-10-05T01:23:29.753-07:00Studying the TPMS signals from Subaru a.k.a. Schrader signals1) Observing the car at standstill produced no signals. Even after driving.<br />
<br />
Data collection: So far windows and HDSDR have been used. SDR# is not available to me, Neither a portable coputer with gnuradio. Recordings produced files that ended like this: 433789kHz_RF.wav Stereosignals in Audacity with something that looked like quadrature detection. Is this the I/Q?<br />
<br />
2) While driving, an some signals were registered, approx one every 14 seconds.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizvmkvQPvRHEO4eb3eZ6N6JIkvO985JmdABmwpRhO6x3ukGcl8CC-jxCZJFeo3w56DgDQf4ERJbRbmSWP1WMTr8M4Rm1MlkIxCVsRJvdCnsUpBJ8JREX09YA_Owg6FsLHHkGzmKVnDCJg/s1600/HELE.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizvmkvQPvRHEO4eb3eZ6N6JIkvO985JmdABmwpRhO6x3ukGcl8CC-jxCZJFeo3w56DgDQf4ERJbRbmSWP1WMTr8M4Rm1MlkIxCVsRJvdCnsUpBJ8JREX09YA_Owg6FsLHHkGzmKVnDCJg/s1600/HELE.PNG" height="205" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6r_jgIGPaqqxXn94Ux2MF1petzqgskMLd_rZ5ea2DIowMY7nTGGco0Wc_t_Z21ug1-IHAePWTF1S1kxGrJVMCXkTqzHz4i2EVDk6uGVxpJ96yOHf17kXBWfRWwDvE93fFYiSizCphKtE/s1600/ASK.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6r_jgIGPaqqxXn94Ux2MF1petzqgskMLd_rZ5ea2DIowMY7nTGGco0Wc_t_Z21ug1-IHAePWTF1S1kxGrJVMCXkTqzHz4i2EVDk6uGVxpJ96yOHf17kXBWfRWwDvE93fFYiSizCphKtE/s1600/ASK.PNG" height="97" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOnbDTbA9h_H4GixiaFvcIs5vJha766iD9FdwQz-JGq4Cr9864hqmjOI5aGoX0m_xT2ikaF0mEZfHPAjukmjAdo4H9gcv9Cmkbib7EIvBnCGeuUfF9vNbvPwyQXBvP8zBt13cYNMAkoI0/s1600/MOD.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOnbDTbA9h_H4GixiaFvcIs5vJha766iD9FdwQz-JGq4Cr9864hqmjOI5aGoX0m_xT2ikaF0mEZfHPAjukmjAdo4H9gcv9Cmkbib7EIvBnCGeuUfF9vNbvPwyQXBvP8zBt13cYNMAkoI0/s1600/MOD.PNG" height="99" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
The first part of the signal is constant, the second part varies. 48 bits. 8 first bits a short pulse. The second part is closer to the resonance frequency. Driving on, I never manage to observe this signal again. Maybe a local, exterior signal?</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
3) After some fiddeling with parameters, some other signal are observed.<br />
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I first processed these data with a low pass filter, then a normalization. Not wise, a repeating signal is also observed without the initial low pass filter:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUZfuL-ST01rVXp4SsBz-xD9kESdxJI-Mo7uk8jSFGAywURrvKW26Bj2kQSCY71LpXLW2ekLf-fynxvioIxbKGQFGQR73pqePQ4B8FjGmHeMptFj9Z0Z-tjDjDb8WjgK6-RGq6WKHK0Sc/s1600/ALWAYS.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUZfuL-ST01rVXp4SsBz-xD9kESdxJI-Mo7uk8jSFGAywURrvKW26Bj2kQSCY71LpXLW2ekLf-fynxvioIxbKGQFGQR73pqePQ4B8FjGmHeMptFj9Z0Z-tjDjDb8WjgK6-RGq6WKHK0Sc/s1600/ALWAYS.PNG" height="314" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Eight groups of packets, separated by 100 ms.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2FGYffmAKZP6qJi5Hv9B_LegMcXqNjhmpc7oMhyphenhyphenXnwHpfJtKTF5Y_yamscLCDjEla62gdxHYeW9gHBbbx1QY250kfzwf1vnjXC-MzHuoC_7B9mjTPwGqFiJvCg5LgedreMsWmuuo8-HI/s1600/ALWAYSZOOMED.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2FGYffmAKZP6qJi5Hv9B_LegMcXqNjhmpc7oMhyphenhyphenXnwHpfJtKTF5Y_yamscLCDjEla62gdxHYeW9gHBbbx1QY250kfzwf1vnjXC-MzHuoC_7B9mjTPwGqFiJvCg5LgedreMsWmuuo8-HI/s1600/ALWAYSZOOMED.PNG" height="224" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br />
The packets are not yet analyzed, could this signal shape indicate FSK? Seems to be three different pulse lengths in the packet. Like Jared Boon is <a href="https://www.youtube.com/watch?v=bKqiq2Y43Wg" target="_blank">taking about</a> here.<br />
<br />
Screendump from HDSDR:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjL13ZERPcZEAJ4Eoy4K33RF9Q_ha9a8HcI6SYSED3nJcNDwjOMABPjBBFYyg3hpd6ww_MBTM9ymOxpd3DZnh3EpzDefZoIQRTw1rqmkZ-VVCKzR_Q6mApECEcrHlmrsizEJ8EVPQLgGfM/s1600/schraderTPMS.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjL13ZERPcZEAJ4Eoy4K33RF9Q_ha9a8HcI6SYSED3nJcNDwjOMABPjBBFYyg3hpd6ww_MBTM9ymOxpd3DZnh3EpzDefZoIQRTw1rqmkZ-VVCKzR_Q6mApECEcrHlmrsizEJ8EVPQLgGfM/s1600/schraderTPMS.PNG" height="352" width="640" /></a></div>
<br />
<br />
<br />dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com4tag:blogger.com,1999:blog-1082071635998277371.post-64150987378879906792014-09-29T07:17:00.001-07:002014-09-29T07:20:22.930-07:00Decoding Biltema Weatherstation 84086 / sensor 84056<br />
This weather station is sold with one remote sensor and a base station capable of monitoring airpressure. It also have a radio controlled clock.<br />
<br />
The remote sensor is capable of measuring temperature and pressure and broadcast this information on the 433 MHz band.<br />
<br />
Using a 433 MHz receiver together with a logic analyzer several things could be learned:<br />
<br />
The sensor transmit 20 bits of information starting with a 1.45 ms pulse followed by 1.50 ms silence. Pulses 2.16 ms long followed by 0.77 ms silence is '1', and 0.70 ms pulses followed by 2.23 ms silence is representing '0'.<br />
<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgApdohRILqjgTCAzGLFQopFYsKxS3kt_8EJT67vvckslMHV32t0xEzv_9rgF6oR_S_wxRV0IQiBYmxR5iqzjelQq-gnpMrBiapmCZINuABKbATs4_9kehtyt1FmOMJQZzvp4mFm7Vm0tE/s1600/biltemablogg.PNG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgApdohRILqjgTCAzGLFQopFYsKxS3kt_8EJT67vvckslMHV32t0xEzv_9rgF6oR_S_wxRV0IQiBYmxR5iqzjelQq-gnpMrBiapmCZINuABKbATs4_9kehtyt1FmOMJQZzvp4mFm7Vm0tE/s1600/biltemablogg.PNG" height="344" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Channel 2, -16.6C, 20% humidity</td></tr>
</tbody></table>
<br />
Several different measurements obtained with varying temperatures and
constant humidity (36% (0b100100)) showed that the sensor transmitted the humidity
in the seven last bits of the transmission.<br />
<br />
The last seven bits is arranged in the following fashion: bit 1, 0 , 6, 5, 4, 3 and 2.<br />
<br />
Yeah, and after some googling I found that the decoded signals were presented at <a href="http://developer.telldus.com/ticket/319" target="_blank">telldus.com</a>.<br />
<br />
In the following table this decoding is used with the exception of me rotating the bitorder.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDp5znkmYzWw5jDNhpzc6GSCp4SgwuSw9J2DED04N0P2rZQqOPrYpYVdI1Oo_WDp2z4tFlg4W1ORsrvlDALCCy4LKepB067hxZjBWw4IrOujUwMVMG3dSPfevgDx2mkgAt5exIHqaVhp8/s1600/biltemablogg2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDp5znkmYzWw5jDNhpzc6GSCp4SgwuSw9J2DED04N0P2rZQqOPrYpYVdI1Oo_WDp2z4tFlg4W1ORsrvlDALCCy4LKepB067hxZjBWw4IrOujUwMVMG3dSPfevgDx2mkgAt5exIHqaVhp8/s1600/biltemablogg2.PNG" height="640" width="458" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5Vcamcxn2fszKiheNr3NbCwgZhmEQtnW20BG7rb0D-8FOh-ONOubej6nZzTj1YfLFfPB5Zsikll2YuUqNOF-D9yghmb6zbrOtpJZr7B_xk_LK0n9MTiiZGvJhycNheruwIZ1hPLLfoyk/s1600/biltemablogg2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><br /></a></div>
<br />
<br />
<br />
<br />dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com0tag:blogger.com,1999:blog-1082071635998277371.post-83468335689326793232014-04-08T07:34:00.002-07:002014-04-10T00:06:09.633-07:00Turning NEXA recievers on and off from the light switchSo, the switch in question is divided into three parts, for controlling three different lights. One of these is an outlet located close to the ceiling, just above a cupboard.<br />
<br />
The most elegant solution would be to hook this outlet up to the device controlling the Nexa switches. Power comes on, send signal for turning on the Nexa switches. Power dissapears, send signal for turning off the Nexa switches.<br />
<br />
This requires us to detect the power off from the outlet and send the OFF signal before the power is totally gone.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmBVMNRYTdn6S5pKskq-f01sqhPdoWhANHjinzCE4MFZFQjxhixU3jsHE9h_QkKAS0dtxkzO1UgAW1SX8GKTcSHjKh1_ZaaMAClytuREcNXBBSK8FRWvvtMDYGxQsAPJO93JG_pOFWp_E/s1600/voltagedropdetector.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmBVMNRYTdn6S5pKskq-f01sqhPdoWhANHjinzCE4MFZFQjxhixU3jsHE9h_QkKAS0dtxkzO1UgAW1SX8GKTcSHjKh1_ZaaMAClytuREcNXBBSK8FRWvvtMDYGxQsAPJO93JG_pOFWp_E/s1600/voltagedropdetector.PNG" height="192" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Using a 9V (more like 12V) 200 mA AC adaptor and hooking the outputs of this circuit to a atiny13A MCU and a standard <a href="http://imall.iteadstudio.com/wireless/im120628014.html" target="_blank">Itead 433 MHz radio</a>, using the attiny13a to detect when the voltage dropped from 'V detect' the following were obtained:<br />
<br />
R1 360 Ohm<br />
R2 180 Ohm<br />
D1 1N4001<br />
C1 1000uF, 50V<br />
Radio operates 650 ms after 'V detect' goes low.<br />
<br />
Since the Nexa transmission requires ca. 400 ms, no modifications to this setup were necessary. The NEXA protocol is described <a href="http://dephiox.blogspot.se/2013/01/decoding-new-nexa-protocol.html" target="_blank">here</a>.<br />
<br />
<br />
The attiny13A is programmed to send the ON signal when the power comes on. It then enters a loop waiting for the voltage indicator to drop and then sends the OFF signal.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6HMeTBgHmbFc9JS8eJHeeC_AHbfZvGlj7vsBm4MmwqhQAR8ykUFoBF6C2HIGlkdOpzv3WVKM9IqnS9tIsIUeeoNzHjzk71TIE7btFgf57DFKzQx9VzoVvZhjnHZ_U2GKXZbJMvw3CTa8/s1600/la.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6HMeTBgHmbFc9JS8eJHeeC_AHbfZvGlj7vsBm4MmwqhQAR8ykUFoBF6C2HIGlkdOpzv3WVKM9IqnS9tIsIUeeoNzHjzk71TIE7btFgf57DFKzQx9VzoVvZhjnHZ_U2GKXZbJMvw3CTa8/s1600/la.PNG" height="256" width="400" /></a></div>
<br />
Voltage drops at '1', radio stops sending at '2'.<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIri6S9c8H5hAm9swAp8vP0UT6BVvVxW2ZHWLt4cGGWeAhgGcR6pXZ1P4nfRLMskzvBV0anZlGpK1mOM7VzQGzaGd58DY3i9lN6g4Q4IJ-1xBkoRLmiRlV5fr6PCnUB-z7UYSgw4bbboXy/s320/codebg.gif); background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> /*
* Lysbryter.c
*
* Created: 4/6/2014 12:11:38 PM
* Author: hwa
*/
#define F_CPU 8000000
#include <avr/io.h>
#include <util/delay.h>
#define RPORT PINB0
void send_signal(uint32_t ID, uint8_t GRP, uint8_t ON, uint8_t UNIT);
void pulse();
void pulse()
{
PORTB |= (1<<RPORT);
_delay_us(230);
PORTB &= ~(1<<RPORT);
}
// delays determining '0' or '1'
#define SHORTDELAY 400
#define LONGDELAY 1420
void send_signal(uint32_t ID, uint8_t GRP, uint8_t ON, uint8_t UNIT)
{
uint16_t t1,t2;
t1 = (ID>>10);
t2 = (ID<<6);
if (GRP==1)
{
t2 |=1<<5; //Group command
}
if (ON==1)
{
t2 |= 1<<4; //ON
}
// ORin UNIT
t2 = t2 | (UNIT & 0x0F);
pulse();
_delay_us(1000);
_delay_us(1000);
_delay_us(825);
for (int i =15;i>=0;i--)
{
if (((t1) & (1 << i)) == 0)//Console::WriteLine("0");
{
pulse();
_delay_us(SHORTDELAY);
pulse();
_delay_us(LONGDELAY);
}
else//Console::WriteLine("1");
{
pulse();
_delay_us(LONGDELAY);
pulse();
_delay_us(SHORTDELAY);
}
}
for (int i =15;i>=0;i--)
{
if (((t2) & (1 << i)) == 0)//Console::WriteLine("0");
{
pulse();
_delay_us(SHORTDELAY);
pulse();
_delay_us(LONGDELAY);
}
else//Console::WriteLine("1");
{
pulse();
_delay_us(LONGDELAY);
pulse();
_delay_us(SHORTDELAY);
}
}
pulse();
}
int main(void)
{
int nopower = 0;
//DDRB &= ~(1<<PINB4);
DDRB=0;
DDRB |= (1<<PINB0); // output
PORTB &= ~(1<<PINB0); //off
//PORTB &= ~(1<<PINB4); //pullup
_delay_ms(100);
// send turn on signal to the group
for (int i =0;i<7;i++)
{
send_signal(0x280526, 1,1,0);
_delay_ms(11);
}
while(1)
{
if(bit_is_clear(PINB, PINB4))
{
nopower = 1;
}
if (nopower==1)
{
for (int i =0;i<7;i++)
{
send_signal(0x280526, 1, 0, 0); //off
_delay_ms(11);
}
}
}
}
</code></pre>
<br />
Looking at the source code it is apparent that one could have used a function 'calculate_signalstring' which returned the bits to send thus eliminating the need for recomputation each time 'send_signal' was executed. '0x280526' is the ID code for my Nexa remote.<br />
<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgq6fAh5Qn5Dx7qwGnqy5sTBY_bFWY0R0fQShi_3hiTAwjsE5ZQGpY5SNlaUC_7qCHtiho4aK3hLERsJ0QM534bqZmL_KS4ga3yYalaw_itTdjkOCSoEsi7Aziv23Wnnim7Nt-MFpCSxfA/s1600/attinysignal.PNG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgq6fAh5Qn5Dx7qwGnqy5sTBY_bFWY0R0fQShi_3hiTAwjsE5ZQGpY5SNlaUC_7qCHtiho4aK3hLERsJ0QM534bqZmL_KS4ga3yYalaw_itTdjkOCSoEsi7Aziv23Wnnim7Nt-MFpCSxfA/s1600/attinysignal.PNG" height="298" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Signal from the ATtiny13A</td></tr>
</tbody></table>
It did appear that the reciever were forgiving with the exact pulsewidth and pulse delays in the sequence. Two initial adjustments were all it took to make the reciever accept the signal.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4x8Vtebqv0MtGFBaxsJkMjVpAjywAsxqpn4AZuG1G9raIkEi2VL97ZaWvGvQgQEYy4aymtodYzXtbzolkbSBNRHFKd68PCg6X9lTn-IQQSZ2xNN_nVskeL7MIVOMGRMHVF9HmNWqeZQg/s1600/remotesignal.PNG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4x8Vtebqv0MtGFBaxsJkMjVpAjywAsxqpn4AZuG1G9raIkEi2VL97ZaWvGvQgQEYy4aymtodYzXtbzolkbSBNRHFKd68PCg6X9lTn-IQQSZ2xNN_nVskeL7MIVOMGRMHVF9HmNWqeZQg/s1600/remotesignal.PNG" height="288" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Signal from the NEXA remote</td></tr>
</tbody></table>
Looking at the last six bits of these patterns it is apparent that the attiny13A is sending the group/off signal while the remote sends the unit 1 on signal.dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com0tag:blogger.com,1999:blog-1082071635998277371.post-8349030525338775782013-12-26T01:35:00.000-08:002013-12-26T03:27:03.986-08:00More on observing the 433MHz band, Nexus IW004One of the Christmas gifts in the family this year was a weather station, "Nexus IW004 / 36-5136". Some 'googling' of the brand got me to one of the local gadget stores in the region, <a href="http://www.clasohlson.com/se/V%C3%A4derstation/36-5136" target="_blank">Clas Ohlson</a>. It is capable of measuring indoor and outdoor temperature and humidity, air pressure and the date. It also predicts the upcoming weather based on these data. The outdoor unit includes a sensor with mounting possibilities attached to the unit with a 1 meter wire.<br />
<br />
Analysing the data with a 433 MHz receiver unit and a logic analyser showed a burst of twelve identical signals, 3.9 ms apart, for each reading of outdoor status. For channel 1 these bursts were located 56.95 seconds apart. For channel 2, 67.05 seconds and for channel 3 84.97 seconds apart.<br />
<br />
Each pulse is 0.47 ms wide, with 1.98 ms separating 'ones' and 0.99 ms separating 'zeros'. The last pulse in a 'burst' is narrower, 0.25 ms wide.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYyQjYY9Q3MxsjcRt2NNY7U9X5OvcauMpWu38C_DuBgU8gmST57q3zuOOodGYsM-Z-gficZYRmVeWbCL3c2orzl1TUGHpB1u_drpBou5_wehsayWAgiSIO0K0lPShJm7e0fAG57KYd8n0/s1600/Screen+Shot+2013-12-25+at+16.58.41.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="155" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYyQjYY9Q3MxsjcRt2NNY7U9X5OvcauMpWu38C_DuBgU8gmST57q3zuOOodGYsM-Z-gficZYRmVeWbCL3c2orzl1TUGHpB1u_drpBou5_wehsayWAgiSIO0K0lPShJm7e0fAG57KYd8n0/s640/Screen+Shot+2013-12-25+at+16.58.41.png" width="640" /></a></div>
<br />
Using this information and by varying the environmental parameters the following table could be compiled:<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBpX2Iekmt5JxQh4rL64IcGcGC2uwP_cK_7O2iGxKMthH3yhDO_D7Tnj9HgloGVI4KzOEOjKnI1kAxtoMBw7CuQLXIF7swnAFJwiI9pKaxVODXwbLEmYL7HXsjYbDMKBzXSS6ufy7hlQ8/s1600/Screen+Shot+2013-12-26+at+10.15.47.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBpX2Iekmt5JxQh4rL64IcGcGC2uwP_cK_7O2iGxKMthH3yhDO_D7Tnj9HgloGVI4KzOEOjKnI1kAxtoMBw7CuQLXIF7swnAFJwiI9pKaxVODXwbLEmYL7HXsjYbDMKBzXSS6ufy7hlQ8/s640/Screen+Shot+2013-12-26+at+10.15.47.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<pre>bit 1 - 10 Sensor ID and battery status(?)
bit 11 - 12 Channel ID
bit 13 - 24 Temperature * 10 in two's complement notation
bit 25 - 28 Always 1
bit 29 - 36 Humidity
</pre>
<br />
<br />
Something also happens in bit 3 - 7 when the channel changes on the outdoor sensor.<br />
<br />dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com0tag:blogger.com,1999:blog-1082071635998277371.post-16764491086432094822013-07-26T02:31:00.001-07:002013-07-26T02:31:09.984-07:00Using the Nexa remote together with a tellstick deviceOne of my Nexa switches is operated programmaticly from a computer via a <a href="http://www.telldus.se/" target="_blank">tellstick</a>. Whenever I want to control this device manually I will log in to the computer and issue the proper commands to operate the switch. However, not everybody finds this procedure acceptable so I needed a way to operate the switch both from the tellstick and from a Nexa remote.<br />
<br />
First I reprogrammed the Nexa switch to accept the Nexa remote.<br />
<br />
Then, by using the hard- and software described in <a href="http://dephiox.blogspot.se/2013/01/decoding-new-nexa-protocol.html" target="_blank">decoding-new-nexa-protocol</a> I could extract the ID code sent from the Nexa remote. This ID code could be directly entered into the "/etc/tellstick.conf" file and after a restart of the tellstick daemon the switch were operable by both the Nexa remote and the tellstick.dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com0tag:blogger.com,1999:blog-1082071635998277371.post-71895561899849954372013-05-28T23:42:00.001-07:002013-05-30T00:47:20.145-07:00Using a MCE remote control with mythtv / xbmc<div>
<br /></div>
<h2>
No lircd please.</h2>
<div>
After five years of mythtv 0.19 / xbmc (no udates of any kind during that time) and <b>numerous</b> restarts of lirc I got myself a new remote with an usb reciever, "MCE remote". A remote that shows up directly in the /dev/input directory of ubuntu 12.04. In addition to some standard buttons it also got a built in mouse. If one presses and holds down one of the numeric buttons it first emit a digit and then, after a while, emit a backspace and a character. E.g: Holding down "2" gives "2", delay, "<bs>A", delay, <bs>B, etc.<br />
<br />
All very handy, but in the end I will probably use the reciever with my learning remote control wich also controls the amplifier and other stuff. </div>
<div>
<br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAA-EHIfduaJZoQK9N67vNM4yTKTFhdeGdU3BKPUxfOTy7Z-mT8I0hjIQLP429614AIRbSZcEIebup_vOn9tYUieyTYq1Ocx4nP0tQ9HGqooJ_H9uC4Zdg19o1VeiB_WaP-ab4_szbE4Q/s1600/fractaldesign.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="117" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAA-EHIfduaJZoQK9N67vNM4yTKTFhdeGdU3BKPUxfOTy7Z-mT8I0hjIQLP429614AIRbSZcEIebup_vOn9tYUieyTYq1Ocx4nP0tQ9HGqooJ_H9uC4Zdg19o1VeiB_WaP-ab4_szbE4Q/s400/fractaldesign.jpg" width="400" /></a></div>
<br /></div>
<div>
<br />
It was bought under the brand name "Fractal design", but as ubuntu concerns this is the important stuff:<br />
(since ubuntu 12.04 lists this device in /dev/input/by-id it is easy to locate, otherwise one could plug/unplug and look in the /dev/input/ directory)</div>
<div>
<br /></div>
<div>
<pre><span style="font-size: x-small;">sudo udevadm info -a --name=/dev/input/by-id/usb-Cypress_Cypress_USB_Keyboard-event-mouse
Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.</span>
<span style="font-size: x-small;">looking at device '/devices/pci0000:00/0000:00:02.0/usb3/3-1/3-1:1.0/input/input2/event2':
<span style="color: red;">KERNEL=="event2"</span>
<span style="color: red;">SUBSYSTEM=="input"</span>
DRIVER==""
looking at parent device '/devices/pci0000:00/0000:00:02.0/usb3/3-1/3-1:1.0/input/input2':
KERNELS=="input2"
SUBSYSTEMS=="input"
DRIVERS==""
ATTRS{name}=="Cypress Cypress USB Keyboard"
ATTRS{phys}=="usb-0000:00:02.0-1/input0"
ATTRS{uniq}==""
ATTRS{properties}=="0"
looking at parent device '/devices/pci0000:00/0000:00:02.0/usb3/3-1/3-1:1.0':
KERNELS=="3-1:1.0"
SUBSYSTEMS=="usb"
DRIVERS=="usbhid"
ATTRS{bInterfaceClass}=="03"
ATTRS{bInterfaceSubClass}=="01"
ATTRS{bInterfaceProtocol}=="01"
ATTRS{bNumEndpoints}=="01"
ATTRS{supports_autosuspend}=="1"
ATTRS{bAlternateSetting}==" 0"
ATTRS{bInterfaceNumber}=="00"
looking at parent device '/devices/pci0000:00/0000:00:02.0/usb3/3-1':
KERNELS=="3-1"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bDeviceProtocol}=="00"
ATTRS{devpath}=="1"
<span style="color: magenta;">ATTRS{idVendor}=="04b4"</span>
ATTRS{speed}=="1.5"
ATTRS{bNumInterfaces}==" 1"
ATTRS{bConfigurationValue}=="1"
ATTRS{bMaxPacketSize0}=="8"
ATTRS{busnum}=="3"
ATTRS{devnum}=="2"
ATTRS{configuration}==""
ATTRS{bMaxPower}==" 98mA"
ATTRS{authorized}=="1"
ATTRS{bmAttributes}=="a0"
ATTRS{bNumConfigurations}=="1"
ATTRS{maxchild}=="0"
ATTRS{bcdDevice}=="0100"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{quirks}=="0x0"
ATTRS{version}==" 1.10"
ATTRS{urbnum}=="12"
ATTRS{manufacturer}=="Cypress"
ATTRS{removable}=="unknown"
<span style="color: magenta;">ATTRS{idProduct}=="0100"</span>
ATTRS{bDeviceClass}=="00"
ATTRS{product}=="Cypress USB Keyboard"</span>
</pre>
<pre><span style="font-size: x-small;">
</span></pre>
In order to remap the remote keys we have to write a keymaps file and run this when the usb reciever are plugged into the system. A great "howto" on this is in <a href="http://www.reactivated.net/writing_udev_rules.html" target="_blank">writing udev rules</a>.
As shown by the '/dev/by-id' contents, the remote control is two units; the mouse part and the rest. The difference between these are the 'KERNEL==' attribute. Since one can use info from the device itself and <b>one</b> of the parent devices I used this rule:<br />
<br /></div>
<pre><span style="font-size: x-small;"><span style="color: red;">SUBSYSTEM=="input"</span>, <span style="color: red;">KERNEL=="event*"</span>, <span style="color: magenta;">ATTRS{idVendor}=="04b4"</span>, <span style="color: magenta;">ATTRS{idProduct}=="0100"</span>, RUN+="/bin/sh -c 'echo $name >> /tmp/test.udev"</span></pre>
<pre><span style="font-size: x-small;">SUBSYSTEM=="input", KERNEL=="event*", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="0100", RUN+="keymap $name cypressusb"</span></pre>
<br />
This is the method I use to convince myself that the udev rules are hit. Just check the '/tmp/test.udev' for which devices that match the rule. '/lib/udev/keymap device keymapfile' (where 'keymapfile' is located in /lib/udev/keymaps/ updates the keymap of the device). To simulate adding devices use
<br />
<br />
<pre><span style="font-size: x-small;">sudo udevadm trigger</span>
</pre>
<br />
<br />
'ir-keytable' may be used to check the keycodes emitted from the remote:<br />
<br />
<pre><span style="font-size: x-small;">#From ir-keytable -t -d /dev/input/by-id/usb-Cypress_Cypress_USB_Keyboard-event-mouse
#Pressing buttons from top left across to the right and down
700e0 KEY_LEFTCTRL (0x001d)
70015 KEY_R (0x0013)
c00b7 KEY_STOPCD (0x00a6)
700e2 KEY_LEFTALT (0x0038)
7003d KEY_F4 (0x003e)
**
700e0 KEY_LEFTCTRL (0x001d)
70005 KEY_LEFT (0x0069)
700e0 KEY_LEFTCTRL (0x001d)
700e1 KEY_LEFTSHIFT (0x002a)
70013 KEY_P (0x0019)
700e0 KEY_LEFTCTRL (0x001d)
700e1 KEY_LEFTSHIFT (0x002a)
70005 KEY_LEFT (0x0069)
**
700e0 KEY_LEFTCTRL (0x001d)
700e1 KEY_LEFTSHIFT (0x002a)
70005 KEY_LEFT (0x0069)
700e0 KEY_LEFTCTRL (0x001d)
70013 KEY_P (0x0019)
700e0 KEY_LEFTCTRL (0x001d)
700e1 KEY_LEFTSHIFT (0x002a)
70009 KEY_RIGHT (0x006a)
**
700e0 KEY_LEFTCTRL (0x001d)
700e1 KEY_LEFTSHIFT (0x002a)
70010 KEY_M (0x0032)
700e2 KEY_LEFTALT (0x0038)
700e3 KEY_LEFTMETA (0x007d)
70028 KEY_ENTER (0x001c)
700e0 KEY_LEFTCTRL (0x001d)
7000a KEY_G (0x0022)
**
70028 KEY_ENTER (0x001c)
7002a KEY_BACKSPACE (0x000e)
70050 KEY_LEFT
70052 KEY_UP
7004f KEY_RIGHT
70051 KEY_DOWN
then the mouse buttons </span></pre>
<pre><span style="font-size: x-small;">
</span></pre>
<pre><span style="font-size: x-small;">left mouse btn 90001 BTN_MOUSE (0x0110)</span></pre>
<pre><span style="font-size: x-small;">right mouse btn 90002 BTN_RIGHT (0x0111)</span></pre>
<pre><span style="font-size: x-small;">
</span></pre>
<pre><span style="font-size: x-small;">and joystick
and continuing...
RecTV
700e0 KEY_LEFTCTRL
70012 KEY_O
Vol+
70043 KEY_F10
Vol-
70042 KEY_F9
Ch/Pg+
7004b KEY_PAGEUP
Ch/Pg-
7004e KEY_PAGEDOWN
LiveTV
700e0 KEY_LEFTCTRL
70017 KEY_T
**
S1 c0223 KEY_HOMEPAGE
S2 c022a KEY_BOOKMARKS
mute 70041 KEY_F8
S3 c0224 KEY_BACK
S4 c0225 KEY_FORWARD
red 700e0 KEY_LEFTCTRL
700e1 KEY_LEFTSHIFT
70017 KEY_T
green 700e0 KEY_LEFTCTRL
70008 KEY_E
yellow 700e0 KEY_LEFTCTRL
7000c KEY_I
blue 700e0 KEY_LEFTCTRL
70010 KEY_M
the numeric keys, and finally...;
clear 7002a KEY_BACKSPACE (0x000e)
enter 70028 KEY_ENTER (0x001c)</span>
</pre>
<br />
The remote dublicates the keycodes sent from the "back" and "clear" buttons and also the "ok" and "enter" buttons.<br />
<br />
Mythtv uses <ESC> as back key, but I don't want to reassign the 'back' key on the remote from backspace, it could be needed. Therefore the first iteration of the keymap would be to reassign left and right mouse button to OK and ESC.<br />
<br />
<pre><span style="font-size: x-small;">/lib/udev/keymaps/cypressusb
0x90001 OK # left mouse btn -> OK
0x90002 ESC # right mouse btn -> ESC</span>
</pre>
<br />
<br />
<br />
<br />dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com0tag:blogger.com,1999:blog-1082071635998277371.post-18919436410002282532013-01-16T10:50:00.003-08:002013-01-17T02:43:55.556-08:00Decoding the "new" NEXA protocol<br />
<h2>
Description of the NEXA protocol</h2>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSAx4hSOG0cfqTLKMPPZTPkGqoIXgBWQdTRmysznD_jsT88MtA165DKwJMu6bOzxW-fRSfOxByMSa-sGeH3V0EJJIo7F0lo8_IJOPXZzF0R2Eobzggp441tLSIDlfOluBlkWp0xK8Uvb0/s1600/Screen+Shot+2013-01-16+at+1.18.29+PM.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="220" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSAx4hSOG0cfqTLKMPPZTPkGqoIXgBWQdTRmysznD_jsT88MtA165DKwJMu6bOzxW-fRSfOxByMSa-sGeH3V0EJJIo7F0lo8_IJOPXZzF0R2Eobzggp441tLSIDlfOluBlkWp0xK8Uvb0/s640/Screen+Shot+2013-01-16+at+1.18.29+PM.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">One burst of data from a NEXA remote.</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
The "new" NEXAprotocol are described <a href="http://www.elektronikforumet.com/wiki/index.php?title=RF_Protokoll_-_JULA-Anslut" target="_blank">here</a>. Basically it is like this: The signal for start TX is a pulse (0.2 ms) followed by a delay of 2.7 ms. A pulse followed by a short delay (0.4 ms) reads as "0". A pulse followed by a longer delay (1.4 ms) reads as "1". The data are then combined into a 32 bit string by assigning "01" as '0' and "10" as '1'.<br />
<br />
<div style="text-align: center;">
<span style="color: red;">00000000001000000000000010</span><span style="color: blue;">0</span><span style="color: red;">1</span><span style="color: blue;">0010</span></div>
<br />
The sequence above were generated from a <a href="http://www.telldus.com/" target="_blank">tellstick</a> using "house=32770" and "unit=3".<br />
The first 26 bits defines the ID of the remote as a binary number. If set, the 27th bit defines the command active for all recievers with the ID ( group command). The 28th bit are the command, '1' for "ON", '0' for "OFF". The last four bits are the unit code. For my NEXA remote control "unit 1" are "0000", "unit 2" are "0001" and "unit 3" are "0010". Every push on the remote generates a train of four pulse bursts, the tellstick generated five.<br />
<br />
<h2>
Decoding</h2>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6KkrPz3WBRPk9T1DD52zLajHrbks7ka6jVb3WjBSH-HMK2gcxCQgaH0UcotRRczewcOc7aRWV8dZKpJky61ZLEXCwjWYhO92IGwLEGnTdcd-dQMI9hZJEmA9pOaRkfyrdJ-FtKIu49wU/s1600/Screen+Shot+2013-01-16+at+1.16.00+PM.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="218" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6KkrPz3WBRPk9T1DD52zLajHrbks7ka6jVb3WjBSH-HMK2gcxCQgaH0UcotRRczewcOc7aRWV8dZKpJky61ZLEXCwjWYhO92IGwLEGnTdcd-dQMI9hZJEmA9pOaRkfyrdJ-FtKIu49wU/s640/Screen+Shot+2013-01-16+at+1.16.00+PM.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">It is noisy in the 433 MHz range and hard to get the first burst of data.</td></tr>
</tbody></table>
It appears that the 433 MHz reciever used are doing level adjustment based on the signal level in the 433 MHz range so the strategy for initiating the decoding were to wait until some data forced the reciever to turn down the gain.<br />
<br />
An Atmega 328P available at hand were chosen to do the decoding. The 433 MHz RX data pin were connected to one of the PCINT22 interrupt pins, PD6. The 16 bit timer1 were used to time pulse widths and delays. Power to the 433 MHz RX unit were provided from PD5 (GND) and PD7 (5V). PC5 were used for debugging by outputting pulses to a logic analyzer. Data were outputted to a LCD screen using code from <a href="http://extremeelectronics.co.in/" target="_blank">extremeelectronics</a>.<br />
<br />
The 328P were run at 8 MHz. A check for how slow it can run and still decode the data are left for later.<br />
<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> /*
* WirelessReader.c
*
* Sample signals from 433 MHz reciver and decode in a state machine.
*
* PCB: SousVide V.1
* Using Using port 11, 12 and 13 (PD5, PD6 and PD7) for 433 MHz RX, drawing ~4 mA
*
*
*
*
*
*/
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include "lcd.h"
#define T01 1
#define T10 0
// shortest and longest accepted pulsewidth
#define kMinPulseWidth 140
#define kMaxPulseWidth 300 //210
// Minimum time between two pulsetrains
#define kPulseTrainDelay 9700
// Minimum time between init pulse and data stream
#define kMinInitDelay 2200 //2600
#define kMaxInitDelay 2800
// Maximum time between two data pulses
#define kMaxDataDelay 1450 //1363
// A delay longer than reads as a '1'
#define kZeroDelay 687 //346
// The data arrives in pairs, '01' or '10', ministate
// keeps track of these pairs
// -1 undefined, waiting for '0' or '1'
// 0 '0' read, waiting for '1'
// 1 '1' read, waiting for '0'
volatile int8_t ministate = -1;
//#state
//# 0 - wait for 9.3 ms (kPulseTrainDelay) silence
//# 1 - wait for and measure init pulse width
//# 2 - measure init delay
//# 3 - check data pulse width and start measuring data delay
//# 4 - read data delay and determine '0', '1'. n time out store data
volatile uint8_t state = 0;
volatile uint32_t rawdata, data;
volatile uint8_t dataready;
//PD5, ground for 433 MHz RX
#define RX_GND_PIN PD5
#define RX_DTA_PIN PD6
#define RX_VCC_PIN PD7
int main(void)
{
// Set up interrupts
PCMSK2 |= (1<<PCINT22);
PCICR |= (1<<PCIE2);
// Set up timer, do not start it
TCCR1B |= (1 << WGM12); //CTC mode
TIMSK1 |= (1<<OCIE1A);
state = 0;
rawdata = 0;
data = 0;
dataready = 0;
// Set up 433MHz RX
DDRD |= (1 << RX_GND_PIN) | (1 << RX_VCC_PIN);
DDRD &= ~(1<<RX_DTA_PIN);
PORTD &= ~(1 << RX_GND_PIN); // set to 0V
PORTD |= (1 << RX_VCC_PIN); // set to 5V
// PORTD |= (1 << RX_DTA_PIN); // pullup
// For debugging
DDRC |= (1 << PC5);
//Initialize LCD module
LCDInit(LS_NONE);//(LS_BLINK|LS_ULINE);
LCDClear();
sei();
while(1)
{
if (dataready==1)
{
cli();
char buff[8];
uint8_t tmp = data &0x000000FF;
sprintf(buff,"%04X", (data>>(16+6))&0x0000FFFF);
LCDWriteStringXY(0,0,buff);
sprintf(buff,"%04X", (data>>6)&0xFFFF);
LCDWriteStringXY(4,0,buff);
if (tmp & 0x10)
{
LCDWriteStringXY(0,1,"ON");
}
else
{
LCDWriteStringXY(0,1,"OFF");
}
// LCDWriteStringXY(4,1,"U ");
// LCDWriteIntXY(6,1,(tmp&0x0f),3);
if ((tmp & 0x0F) == 0x00) LCDWriteStringXY(4,1,"U 1");
if ((tmp & 0x0F) == 0x01) LCDWriteStringXY(4,1,"U 2");
if ((tmp & 0x0F) == 0x02) LCDWriteStringXY(4,1,"U 3");
if (tmp & 0x20) LCDWriteStringXY(4,1,"Grp");
sei();
for (int ii=0;ii<100;ii++)
{
_delay_ms(30);
}
dataready = 0;
cli();
LCDClear();
sei();
}
}
}
//reset state to initial
void inline resetstate()
{
unsigned char sreg;
state=0;
ministate=-1;
data = 0;
rawdata = 0;
TCCR1B &= ~(1 << CS11); //stop timer 1
sreg = SREG; // save global interrupt flag
cli();
TCNT1 = 0;
SREG = sreg; // restore interrrupt flag
}
// start timer
void inline starttimer(int v)
{
unsigned char sreg;
sreg = SREG; // save global interrupt flag
cli();
TCNT1 = 0;
OCR1A = v;
SREG = sreg; // restore interrrupt flag
TCCR1B |= (1 << CS11); //prescale 8
}
// This interrupt is called when the 433 MHz RX pin changes state
ISR(PCINT2_vect)
{
char transition;
// determine the state change direction, 0->1 or 1->0
if (PIND & (1<<PIND6))transition = T01;
else transition = T10;
//state 0: should time out, we need 9.3 ms silence, otherwise try again
if (state == 0)
{
starttimer(kPulseTrainDelay-100);
return;
}
// state 1: we had a 9.3 ms delay, now we are recieving the init pulse
// start the pulsewidth timer
if ((state==1) && (transition == T01))
{
starttimer(kMaxPulseWidth);
return;
}
if ((state==1) && (transition == T10))
{
if (TCNT1<kMinPulseWidth)
{
resetstate();
return;
}
else // pulse OK, too long and it will time out in the timer part
{
state = 2;
starttimer(kMaxInitDelay);
return;
}
}
// state 2: measure the init delay
if (state == 2)// && (transition == T01))
{
if (transition == T10)
{
resetstate();
return;
}
if (TCNT1<kMinInitDelay) // to short
{
resetstate();
return;
}
else // delay OK, too long and it times out
{
starttimer(kMaxPulseWidth);
rawdata = 0;
state = 3;
return;
}
}
//state 3: check pulsewidth in data transmission
if ((state == 3))// && (transition==T10))
{
if (TCNT1<kMinPulseWidth)
{
resetstate();
return;
}
else // pulse OK, too long and it will time out from the timer
{
starttimer(kMaxDataDelay);
state = 4;
return;
}
}
//state 4: read data, '0' or '1'
if (state == 4)
{
int t = TCNT1;
//observing 1310 or 320
if (t > kZeroDelay) // we read '1'
{
if (ministate==1) // error, two '1' in a row
{
resetstate();
return();
}
else if (ministate==-1) // OK, next bit should be '0'
{
ministate = 1;
}
else if (ministate==0) // OK, bit pair completed
{
ministate = -1;
rawdata = (rawdata<<1);
// no need to add '0'
}
}
else // we read '0'
{
if (ministate==0) // error, two '0' in a row
{
resetstate();
return();
}
else if (ministate==-1) // OK, next bit should be '1'
{
ministate = 0;
}
else if (ministate==1) // OK, bit pair completed
{
ministate = -1;
rawdata = (rawdata<<1);
rawdata +=1;
}
}
state = 3;
starttimer(kMaxPulseWidth);
return;
}
}
ISR(TIMER1_COMPA_vect)
{
if (state==0)
{
state = 1;
TCCR1B &= ~(1 << CS11); //stop the timer
return;
}
// pulsewidth/delay were to long
if ((state == 1) || (state == 2) || (state == 3))
{
PORTC = 0b00100000;
PORTC = 0b00000000;
_delay_us(5);
PORTC = 0b00100000;
PORTC = 0b00000000;
resetstate();
return;
}
// end of data burst, wait for next burst
if (state==4)
{
data = rawdata;
rawdata = 0;
dataready=1;
starttimer(kPulseTrainDelay>>1);
state = 0;
}
}
</code></pre>
<br />
This extracts the data in the pulsetrain, but it does not do any accumulation of the data in the pulse trains. Usaully there are at least four bursts that contains the same data.dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com1tag:blogger.com,1999:blog-1082071635998277371.post-36860489717003692102012-12-17T23:26:00.000-08:002012-12-17T23:26:50.340-08:00A state machine for decoding 433 MHz signals<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtxV_4o1JLk3iqslHZkSayeiWyTzlZPLcJlVzMwMQ9i-Ck4LOJs6Jub_LPlfJKWWV-lk_f1qutLobbWq3C0qDmrZ9atRrAYCgbAbKyXS00hpFLYySvU4EnyhZn0CjZjCAnDXApMHJQ_jE/s1600/stateexamples.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="317" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtxV_4o1JLk3iqslHZkSayeiWyTzlZPLcJlVzMwMQ9i-Ck4LOJs6Jub_LPlfJKWWV-lk_f1qutLobbWq3C0qDmrZ9atRrAYCgbAbKyXS00hpFLYySvU4EnyhZn0CjZjCAnDXApMHJQ_jE/s400/stateexamples.png" width="400" /></a></div>
The figure above are a plot of the response at 433 MHz versus time. If one would decode this signal there are three different states one should consider:<br />
<br />
<br />
<ul>
<li>0 - Wait for signal. In this state we have not seen any signals yet.</li>
<li>1 - Peak detected. We want to determine if this is a valid peak for us.</li>
<li>2 - Delay detected. Here we want to determine if the delay is valid. It should not be to short, not to long and it could also be a "0" or a "1". If we have recieved all our expected bits we should store the packet and look for more packets.</li>
</ul>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_HIpERkhfmEnkxwxpaKdl6Sb08NBsnS81hdYRp4Ee-qHAPzZisOBAimvuRe-CHj3iIbjwdxQ_dFC1gvYwTu5pUrM-jlZNSUwepvLmvhL0F6wsN6w4ef-bZhLbwcog2CtWMpxTOgYY_po/s1600/statediagram.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="214" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_HIpERkhfmEnkxwxpaKdl6Sb08NBsnS81hdYRp4Ee-qHAPzZisOBAimvuRe-CHj3iIbjwdxQ_dFC1gvYwTu5pUrM-jlZNSUwepvLmvhL0F6wsN6w4ef-bZhLbwcog2CtWMpxTOgYY_po/s640/statediagram.png" width="640" /></a></div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
<div>
Instead of hacking with some microcontroller, that eventually will do this decoding, I wrote up a python program to do this offline. Files from the logic analyser running at 1 MHz sampling rate are sendt through the python program. The program calls a function everytime the input changes, simulating a interrupt pin on a MCU. It also increases a count for each entry in the file, simulating a 1MHz timer.<br />
<br />
<pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: black; word-wrap: normal;"> #return the "port" state, 1 if transmission otherwise 0
def readport(line):
return int(line.split('\t')[1])
# a pulse is ca 387
# init ca 9617
# 1 is ca 4600
# 0 is ca 2060
#state
# 0 - wait for pulse
# 1 - make sure the pulse is of correct length, 200 to 500
# 2 - measure delay, "init", "0","1" or "illegal" delay
# simulate interrupt due to pin state change
def statechange():
global state, counter, res, timer
if nextportstate == 1: # we are going from 0 -> 1
transition = 1
else:
transition = 2 #from 1 -> 0
#print debugtime, state, res
if state == 0 and transition == 1: # possible transmission/pulse detected
state = 1
timer = 500 #time out after 500
counter = 0 # reset timer
return
if state == 0 and transition == 2: # disregard
state = 0
timer = 0
counter = 0
return
if state == 1: #(and transition == 2):
if transition ==1 or counter < 200: #200
#print "counter " , counter
#print "ERROR in state==1"
state = 0
timer = 0
counter = 0 # reset timer
else: # we detected a legal pulse, determine delay length
# 0 < delay 1500 illegal, goto state 0
# 1500 < delay < 2500 legal, "0"
# 2500 < delay <5000 legal "1"
# 5000 < delay < 8000 illegal, goto state 0
# 9000 < delay 11000 legal, init delay
# 11000 < delay illegal, state 0
state = 2
timer = 10000
counter = 0 # reset timer
return
if state == 2: #(and transition == 1)
if transition == 2: #and counter < 8000:
print "ERROR in state==2"
state = 0
timer = 0
counter = 0
else: #legal init delay
#print "counter state==2 ",counter
if counter > 9000: # init pulse, reset data
print "RES", res
res = ''
state = 1
timer = 500
counter = 0
elif counter > 4000: #got a "1"
res = res + "1"
#print res
state = 1
timer = 500
counter = 0
elif counter > 1700: #got a "0"
res = res + "0"
#print res
state = 1
timer = 500
counter = 0
else: # illegal, to short
res = ""
state = 0
timer = 0
counter = 0
if len(res) == 28:
print "RES", res
res = ''
state = 0
timer = 0
counter = 0
return
#simulate interrupt due to timer
#if something times out it is du to a to long pulse or delay
# we will return to state==0
def timerint():
global state, counter, timer
state = 0
timer = 0
counter = 0
#fp = open("untitled.tsv", "r") #noisy data
fp = open("untitled13.tsv", "r")
data = fp.readlines()
fp.close()
# timer
# 0 do not time out
#
timer = 0
print "file read"
transition = 0
# 0 no change
# 1 low to high
# 2 high to low
counter = 0 # simulate an interrupt counting
portstate = 0
nextportstate = 0
debugtime = -1
res = "XXX"
timer = 0
state = 0
for l in data:
#print debugtime, state, counter,timer
if timer > 0:
if counter>= timer:
timerint()
#counter = 0
counter = counter + 1
debugtime = debugtime + 1
#print debugtime, portstate
if portstate != nextportstate:
callint = 1
else:
callint = 0
portstate = nextportstate
nextportstate = readport(l)
if callint==1:
statechange()
#res 0100010100011111100100110100
# 0100010100011111100100110100
</code></pre>
<br />
This python program works as expected, at least as long as the signal quality is good.</div>
<br />
Making the signal weaker tend to split the peaks into several, shorter peaks, sending the routine back to state "0" without recording any transmission. It is not clear if this should be adressed.<br />
<br />
Only a real test on an MCU could provide that answer.dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com0tag:blogger.com,1999:blog-1082071635998277371.post-33519447756933319932012-12-11T06:47:00.002-08:002012-12-11T10:39:09.292-08:00Replacing toner in my Brother HL-2030During the weekend the toner lamp in my laser printer turned on.<br />
<br />
Checking the largest online suppliers here in Sweden, I noticed that they wanted almost as much for a 2500 pages toner cartridge as I had paid for the laser printer itself.<br />
<br />
This situation reminded me somewhat of the situation with ink jet printers, they are sold cheap or given away with computer purchases. The trick being that the ink in the printer are almost empty already, forcing their unsuspecting customers to a buy expensive ink almost immediately.<br />
<br />
Probably a wise thing to do as well, I have never considered the ink/toner level in a printer when I considered buying it.<br />
<br />
According to Brother the HL-2030 came with a 1500 page toner supply. There exists a standard, ISO/IEC-19752 that defines a standard page. I can not complain, pressing the "Go" button on the printer three times produced a page telling me that I had printed out 1594 pages.<br />
<br />
After some "googling" I found a company, <a href="http://www.nordicink.se/" target="_blank">nordicink.se</a>, that promised to deliver a toner cartridge for approximately one-third of the price of the original toner cartridge sold by my regular office material suppliers.<br />
<br />
I ordered the cartridge on a Saturday, the following Monday I received an SMS telling me that it were in the postal system and today, Tuesday it were in my mailbox. Not bad. The replacement instructions were understandable and the first pages printed looks completely as expected. Now all that remains to discover are when the toner lamp turn on again.dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com0tag:blogger.com,1999:blog-1082071635998277371.post-19627216895090026252012-12-08T00:35:00.001-08:002012-12-08T01:05:06.509-08:00Writing data to the Denver TRC-1480One useful aspect of knowing the protocol used by a wireless thermometer would be to add own sensors. The Denver TRC-1480 have three available channels where one could display custom data. It is also possible to buy additional sensors from Denver.<br />
<br />
<div>
By sending a temperature packet identical to a packet the Denver sensor could have sent one may check how sensitive the Denver decoder are to timing issues.</div>
<div>
<br /></div>
<div>
The test revealed that the decoder only scans for data a few seconds each time it expects a transmission, but once this were addressed the Denver decoder were not very picky about the timing and bits sent.</div>
<div>
<br /></div>
<div>
Sending "01111" as bits 32 - 36 always displayed the intended temperature so the purpose of these bits are somewhat unclear.</div>
dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com0tag:blogger.com,1999:blog-1082071635998277371.post-39364847760042387862012-12-06T11:23:00.000-08:002012-12-08T00:37:20.547-08:00Observing the 433MHz bandI recently "stumbled" over a 433 MHz transmitter-receiver set from <a href="http://imall.iteadstudio.com/wireless/radio-frequency/im120628014.html" target="_blank">iteadstudio</a>. Hooking the receiver up to my <a href="http://www.saleae.com/logic" target="_blank">logic analyzer</a> I could observe three different signals that appeared regularly, 30 - 60 seconds,<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgMlYqtNC8k4fitlbEvsA5QN1qjNO1AUGNyqxS22yJW0ztMfRi_zGnjLjDkL-tR0FZhyphenhyphenBnXpqdnUjPx_kXsGkwyJsVBwuNukZFElhKL6sCcLpsIac0ggwzOdZEOroM5wq5B6RBwfquXnQ/s1600/Screen+Shot+2012-12-06+at+5.21.01+PM.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="60" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgMlYqtNC8k4fitlbEvsA5QN1qjNO1AUGNyqxS22yJW0ztMfRi_zGnjLjDkL-tR0FZhyphenhyphenBnXpqdnUjPx_kXsGkwyJsVBwuNukZFElhKL6sCcLpsIac0ggwzOdZEOroM5wq5B6RBwfquXnQ/s400/Screen+Shot+2012-12-06+at+5.21.01+PM.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Signal 1</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKs3U6Bx7UbspSqckIra4W8PcGv8OBWPyCspQQhlV4rxbPn-AI4Sax0oeoOrNdoqCH6COlY3cBelDfJFIPYPymTT_a1S-8T27EXlgbMTqkm_sqdesRgPjFirXsltX0RAarugnG2KwwjJM/s1600/Screen+Shot+2012-12-06+at+5.33.59+PM.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="53" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKs3U6Bx7UbspSqckIra4W8PcGv8OBWPyCspQQhlV4rxbPn-AI4Sax0oeoOrNdoqCH6COlY3cBelDfJFIPYPymTT_a1S-8T27EXlgbMTqkm_sqdesRgPjFirXsltX0RAarugnG2KwwjJM/s400/Screen+Shot+2012-12-06+at+5.33.59+PM.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Signal 2</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvcJG5VrlqKGcNyomablse64lC2YhBd6PbFovxCP_yGvd_IxnKu9TNnDKS5v3_PPbK1dZ1DGgarhBhF7JwLFpOW9HaN16bM48_XqdYpm83g8N7RfBXqjC1AhLF-cL1mbmHQWfElf7MRu8/s1600/Screen+Shot+2012-12-06+at+5.58.55+PM.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="55" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvcJG5VrlqKGcNyomablse64lC2YhBd6PbFovxCP_yGvd_IxnKu9TNnDKS5v3_PPbK1dZ1DGgarhBhF7JwLFpOW9HaN16bM48_XqdYpm83g8N7RfBXqjC1AhLF-cL1mbmHQWfElf7MRu8/s400/Screen+Shot+2012-12-06+at+5.58.55+PM.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Signal 3</td></tr>
</tbody></table>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Signal 1 were repeated 12 times in a burst and signal 3 were repeated a little bit more than 8 times, leaving the ninth repetition partially complete.<br />
<br />
Signal 1 were easy to identify, it disappeared when I stopped my wireless thermometer...<br />
<br />
<h4>
Signal 1, decoding the Denver TRC-1480</h4>
The Denver TRC-1480 have the possibility to read from three different temperature sensors.<br />
All pulses are of the same length, 0.55 ms with different delays in between. Each packet starts with a pulse and a 4.4 ms delay. Each "1" is a pulse with a 2.45 ms delay and a "0" is a pulse with a 1.45 ms delay.<br />
By varying different parameters the following information were revealed:<br />
<code><br /></code>
<code>
bit 1 - 8 sensor ID</code><br />
<code>bit 9 0 indicates low battery</code><br />
<code>bit 10 always 0</code><br />
<code>bit 11 - 12 channel-1</code><br />
<code>bit 13 - 24 temperature * 10 as two's complement (invert all bits,</code><br />
<code> add 1 and negate for numbers starting with "11".</code><br />
<code>bit 25 - 28 always 1</code><br />
<code>bit 29 - 31 always 0</code><br />
<code>bit 32 - 36 some sort of checksum?</code><br />
<code><br /></code>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXEA_zY2Z4hpJqn-XOrnRyDUM8lST_0lWvAAxDJJhxmHa0r1Ef2AT2pzWu8gntZO-kUxR5nz9ue8rWHJBmKicMKWrTJf44Zm-b4xLJdd-9NyYLsk5ZC1_JmlhPP-a8PoRNmuD-70R1jKw/s1600/Screen+Shot+2012-12-06+at+6.53.37+PM.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="72" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXEA_zY2Z4hpJqn-XOrnRyDUM8lST_0lWvAAxDJJhxmHa0r1Ef2AT2pzWu8gntZO-kUxR5nz9ue8rWHJBmKicMKWrTJf44Zm-b4xLJdd-9NyYLsk5ZC1_JmlhPP-a8PoRNmuD-70R1jKw/s400/Screen+Shot+2012-12-06+at+6.53.37+PM.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Some readings from channel 3</td></tr>
</tbody></table>
<code><br /></code>In addition channel 1 sends at 57 seconds interval, channel 2 at 67 seconds and channel 3 at 80 seconds.<br />
<h3>
Signal 2, unknown origin</h3>
<div>
Transmits every 48 seconds. Consists of 0.5 ms "short" pulses and 1.5 ms "long pulses. A short pulse indicates a "0" and a long pulse a "1". The transmission starts with eight "0". The signal are sometimes very weak.</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div>
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBlFpIL-ltCGRq0xDxy3erayZNiEvxBreN0Tuluo1NoHiNE1OxhqAVFo5xj2W1sl06QjOsahYmNMeda8EYFd9DBXA5gakmqRt3pbcYRYTwLsUBpgZhSUUDAcSarBM7ALOj3-sxeSkoTuo/s1600/Screen+Shot+2012-12-06+at+7.29.08+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="52" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBlFpIL-ltCGRq0xDxy3erayZNiEvxBreN0Tuluo1NoHiNE1OxhqAVFo5xj2W1sl06QjOsahYmNMeda8EYFd9DBXA5gakmqRt3pbcYRYTwLsUBpgZhSUUDAcSarBM7ALOj3-sxeSkoTuo/s640/Screen+Shot+2012-12-06+at+7.29.08+PM.png" width="640" /></a></div>
<div>
<br /></div>
<div>
Bit 17 to 24 may be correlated to the outside temperature by subtracting 234 and dividing by 10. There have to be more to this since the temperature reading with those eight bits are limited to -23.4 to 2.1C. [EDIT:] Or the temperature may be stored as two's complement as well.[]</div>
<div>
I do not yet know the brand of this thermometer.</div>
<div>
<br /></div>
<h3>
Signal 3, unknown origin</h3>
<div>
Transmits every 36 seconds. Consists of 0.4 ms pulses with either 4.6 ms ("1") or 2.4 ms ("0") delays. Each signal frame starts with a pulse followed by a 9.6 ms. delay.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgH9c6vWQXGps3e23HCd6XfGTKA1LTXP4b1vqhr4lxHc7YGnmoh8d6boXlwGcpbZmuazh59Rs0_xl_DRAaXyIBYw2JdTbiQ0ZQL8A-zGvQSSNybIepGHPtIsnoxob9O-sK4eHbY3icd5dY/s1600/Screen+Shot+2012-12-06+at+7.49.02+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="54" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgH9c6vWQXGps3e23HCd6XfGTKA1LTXP4b1vqhr4lxHc7YGnmoh8d6boXlwGcpbZmuazh59Rs0_xl_DRAaXyIBYw2JdTbiQ0ZQL8A-zGvQSSNybIepGHPtIsnoxob9O-sK4eHbY3icd5dY/s640/Screen+Shot+2012-12-06+at+7.49.02+PM.png" width="640" /></a></div>
<div>
<br /></div>
<div>
Bits 17 to 24 correlates to the temperature by subtracting 238 and dividing by 10.<br />
[EDIT:] Or the temperature may be stored as two's complement as well.[]<br />
As with signal 2, clearly more data are needed to assign the different bits.</div>
<div>
<br /></div>
<div>
<br /></div>
<h3>
Sources used</h3>
<div>
A description of some Lacrosse sensors, <a href="http://www.f6fbb.org/domo/sensors/index.php" target="_blank"> Jean-Paul ROUBELAT - F6FBB @ http://www.f6fbb.org</a></div>
<div>
A very informative series from <a href="http://lucsmall.com/2012/04/27/weather-station-hacking-part-1/" target="_blank">spook @ http://lucsmall.com</a> regarding Fine Offset Electronics instruments.</div>
<div>
An eye opener from <a href="http://bertrik.sikken.nl/433mhz/index.html" target="_blank">bertrik</a>.</div>
<div>
<br /></div>
<h3>
More important things yet to be followed up</h3>
<div>
<a href="http://elektronikforumet.com/forum/viewtopic.php?f=2&t=41394&hilit=termometer" target="_blank">http://elektronikforumet.com/forum/viewtopic.php?f=2&t=41394&hilit=termometer</a></div>
<div>
<a href="http://www.cosc.canterbury.ac.nz/greg.ewing/essays/CRC-Reverse-Engineering.html" target="_blank">http://www.cosc.canterbury.ac.nz/greg.ewing/essays/CRC-Reverse-Engineering.html</a></div>
<div>
<a href="http://fredboboss.free.fr/tx29/tx29_crc.php" target="_blank">http://fredboboss.free.fr/tx29/tx29_crc.php</a></div>
<div>
<a href="http://web.archive.org/web/20040826224422/http://www.mellander.org/per/projects/?project=nexa" target="_blank">http://web.archive.org/web/20040826224422/http://www.mellander.org/per/projects/?project=nexa</a></div>
<div>
<a href="https://github.com/kevinmehall/rtlsdr-433m-sensor/tree/91f9d4b5e9854eb0051e7e26e6a71b062251ffdf" target="_blank">https://github.com/kevinmehall/rtlsdr-433m-sensor/tree/91f9d4b5e9854eb0051e7e26e6a71b062251ffdf</a></div>
<div>
<a href="http://jeelabs.net/projects/cafe/wiki/Decoding_the_Oregon_Scientific_V2_protocol" target="_blank">http://jeelabs.net/projects/cafe/wiki/Decoding_the_Oregon_Scientific_V2_protocol</a></div>
<div>
<a href="http://roel.reijerse.net/thierry/" target="_blank">http://roel.reijerse.net/thierry/</a></div>
<div>
<br /></div>
dephioxhttp://www.blogger.com/profile/12762337463870013678noreply@blogger.com3