Improved HP WBEM cmdlets

2016-07-19 2 comments

A few years ago, I wrote a couple of posts about how to gather HP server hardware information from WMI with the HP Insight Management WBEM providers.

https://perhof.wordpress.com/2013/05/08/gather-hp-server-disk-information-using-powershell/
https://perhof.wordpress.com/2014/03/11/gather-hp-ilo-information-using-powershell/

I have used my cmdlets frequently and have since I wrote the above posts improved the cmdlets bit by bit by adding error handling where it has been needed and correcting bugs.
I have written more cmdlets and I’ve merged them all into one PowerShell module that is available for download on Github.

https://github.com/perhof/hp-wbem

For those who want to get their hands dirty and expand the functions, the current code doesn’t have any comments but it should be possible to follow what it does anyway.

Categories: Computing, Windows

Outlook Anywhere in Outlook 2016 with Exchange 2010

2016-06-24 Leave a comment

With a default Outlook Anywhere 2010 and Outlook configuration it takes around 30 seconds after startup before an Outlook client connects to the Exchange server. The reason is that the Exchange 2010 Autodiscover service tells the client to try a regular RPC/TCP connection before resorting to a RPC/HTTP connection. This was easy to change in previous versions of Outlook but not in Outlook 2016.
I’ve seen plenty of people complaining about it on the Technet forums and elsewhere but I haven’t seen anyone getting a solution but I’ve found a few ways to solve the problem.

Outlook 2013 connection settings

Let’s look at how this was handled in Outlook 2013.
The easiest way was to go into account options and modify the connection settings by checking the On fast networks, connect using HTTP first, then connect using TCP/IP option.

Outlook2013ModifiedProxySettings

Fast networks are all network interfaces with a link speed higher than 128Kbps which pretty much means all network interfaces unless you’re toying around with some obsolete dialup adapter.

Outlook 2016 connection settings

Now let’s look at the Outlook 2016 Connection settings.

Outlook2016ConnectionTabMissing
That’s right. There are no Connection settings in Outlook 2016 and that’s because Outlook doesn’t expose any ways of configuring an Exchange server connection other than Autodiscover.

It is possible to set Exchange Server 2010 to prefer HTTP before TCP/IP (or rather RPC/HTTP before RPC/TCP) but that means that all clients will pick up that setting and all clients will connect to your CAS using HTTP, even clients on internal networks.
This is done using the Set-OutlookProvider Cmdlet in Exchange Management Shell:

Set-OutlookProvider EXPR -OutlookProviderFlags:ServerExclusiveConnect

The Set-OutlookProvider Cmdlet is documented at https://technet.microsoft.com/en-us/library/bb123683(v=exchg.141).aspx

As stated in the above documentation, running all connections over HTTP is not recommended for Exchange 2010 unless most clients use Outlook Anywhere as their primary connection method (it is recommended for Exchange 2013 and Exchange 2016 though).

“The OutlookProviderFlags parameter specifies that Outlook 2010 clients should connect using RPC over HTTP (Outlook Anywhere) before trying RPC over TCP connections. This increases the speed at which Outlook 2010 clients will connect when clients are primarily accessing Exchange over the Internet. The value can be set to ServerExclusiveConnect or to None to clear the flags. For Outlook 2010 clients that access Exchange over both organization intranets and the Internet, the recommended value is None, which is also the default setting.”

Configuring connection settings using group policy

It turns out that you can also configure the connection settings using Group Policy the same way as in earlier versions of Outlook.
This could be a better way if your clients mainly connect to Exchange from Internal networks but you still want to configure some clients for quick Outlook Anywhere access.

The GPO settings are found here:
User Configuration\Administrative Templates\Microsoft Outlook 2016\Account Settings\Exchange

Outlook2016PolicyRpcHttpConnectionFlags

The GPO settings that control the options previously found on the Connection tab are:

  • RPC/HTTP Connection Flags
  • RPC Proxy Authentication Setting
  • RPC Proxy Server Name
  • Only connect if Proxy Server certificate has this principal name

The Exchange 2010 Autodiscover functionality provides most values needed and the only thing you should need to change is to enable flag 4 of the RPC/HTTP Connection Flags.
The flags in the RPC/HTTP Connection Flags are:

  • 1: Enables the ‘Connect to Microsoft Exchange using HTTP checkbox’ on the Connection tab.
  • 2: Enables the ‘Connect using SSL only’ checkbox
  • 3: Enables the ‘Only connect to proxy servers that have this principal name in their certificate’ checkbox
  • 4: Enables the ‘On fast networks, connect using HTTP first, then connect using TCP/IP’ checkbox
  • 5: Enables the ‘On slow networks, connect using HTTP first, then connect using TCP/IP’ checkbox

I have used Flags 1+2+3+4+5 which enables all checkboxes the way it used to look in Outlook 2013 for me.

If you don’t have a way to target only your Outlook Anywhere users or you don’t want to use a GPO for some reason you can use the registry to apply these policy settings too.

They registry key where the below values should be stored is:

HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\16.0\Outlook\RPC

The registry path normally doesn’t exist and has to be created.

Values and meanings

  • ProxyServerFlags (DWORD)
    Corresponds to the “RPC/HTTP Connection Flags” policy
    Can have one of the following decimal values:

    • 0 (Not configured = Autodiscover)
    • 33 (Flags 1+5)
    • 35 (Flags 1+2+5)
    • 39 (Flags 1+2+3+5)
    • 41 (Flags 1+4+5)
    • 43 (Flags 1+2+4+5)
    • 47 (Flags 1+2+3+4+5)
  • ProxyAuthenticationService (DWORD)
    Corresponds to the “RPC Proxy Authentication Setting” policy
    Can have one of the following decimal values:

    • 1 (Basic Authentication)
    • 2 (NTLM)
    • 3 (Negotiate)
    • 4 (Certificate)
  • ProxyServerName (Expandable String Value)
    Corresponds to the “RPC Proxy Server Name” policy
    Your Outlook Anywhere host name. I.e. mail.fourthcoffee.com
  • ProxyServerPrincipalName (Expandable String Value)
    Corresponds to the “Only connect if Proxy Server certificate has this principal name” policy
    Your Outlook Anywhere principle name prefixed by msstd:
    I.e. msstd:mail.fourthcoffee.com

 

Categories: Software, Windows, Computing

Reverse engineering Hitachi air conditioner infrared remote commands

2015-03-29 5 comments

Updated 2 April 2015

Background

As part of a home automation project me and a friend started to reverse engineer the infrared remote control protocol used by a Hitachi split type air conditioner. The model in question was a RAS-25SX8 (manual here) but there is no reason to believe that the protocol isn’t the same for many other models and the methods we used to reverse engineer the codes should work with pretty much any remote control.

Most remote controls or at least the remote controls we’ll be talking about here work by sending a series of 38KHz PWM pulses mixed with pauses of various length.
Finding out the length of the PWM pulses and the length of the pauses between them is the key to cracking the protocol.
A remote control for a TV usually sends a code of one byte or so telling which key the user is pressing and it keeps sending the same code over and over until the key is released. There is a different code for each key on the remote control.
Air conditioner codes on the other hand are quite long because it’s the remote control that keeps track of the settings and it sends the complete set of settings everytime a key is pressed.

The only information we managed to find about any Hitachi remote control protocols was this blog: http://mroxanas.blogspot.com/2011/09/infrared-remote-control-code-hacking.html

They managed to turn a device on or off using recorded codes but provide no source code so we couldn’t quite wrap our heads around how to send the codes. We also wanted to do a bit more than just turning on and off so we started to dig.

Aquiring authentic commands

We first needed to take a look at code from a real remote control to get an understanding about how it’s constructed.

As suspected and as mroxanas mentioned, the codes used are quite long – much longer than we managed to record using Arduino and some standard IR libraries such as Arduino-IRremote.
In the end we decided to go with an Arduino sketch from analysir.com with which we managed to record several long codes which all seemed consistent enough to be correct recordings. The sketch can be found at http://www.analysir.com/blog/2014/03/19/air-conditioners-problems-recording-long-infrared-remote-control-signals-arduino/

The AnalysIR sketch dumps puls lengths and pause lengths in microseconds like this:

Raw: (595) 3280, -1704, 468, -1168, 472, -400, 448, -428, 444, -428, 444, -428, 444, -428, 448, -428, 444, -432, 444, -428, 444, -432, 444, -428, 444, -428, 444, -1192, 468, -404, 444, -428, 444, -436, 440, -432, 444, -428, 444, -428, 444, -428, 444, -432, 444, -428, 444, -428, 444, -436, 440, -432, 444, -432, 440, -428, 444, -432, 444, -428, 444, -428, 444, -1188, 472, -408, 444, -1188, 448, -1188, 444, -1188, 448, -1188, 444, -1192, 444, -1188, 444, -432, 444, -1192, 444, -1192, 444, -1188, 444, -1192, 444, -1188, 448, -1188, 444, -1188, 448, -1188, 444, -1196, 444, -428, 444, -428, 444, -432, 440, -432, 444, -428, 444, -428, 444, -432, 444, -432, 444, -428, 444, -428, 444, -1192, 444, -1192, 444, -428, 444, -428, 444, -1192, 444, -1192, 448, -1188, 444, -1188, 448, -428, 444, -428, 444, -1188, 448, -1188, 444, -428, 444, -436, 444, -1188, 472, -1164, 444, -1188, 472, -404, 444, -428, 444, -1188, 448, -428, 444, -1192, 444, -432, 444, -428, 444, -428, 444, -1188, 448, -1188, 448, -428, 444, -1188, 444, -432, 444, -432, 444, -428, 444, -1188, 448, -428, 444, -428, 444, -428, 444, -1192, 444, -432, 444, -1192, 444, -1188, 444, -428, 448, -1188, 444, -1188, 448, -1188, 444, -432, 444, -1192, 444, -432, 440, -432, 444, -1188, 472, -400, 448, -428, 444, -1188, 444, -1192, 468, -408, 444, -1192, 468, -1164, 448, -428, 444, -1188, 444, -1192, 468, -404, 444, -428, 444, -1196, 444, -428, 444, -428, 444, -432, 444, -428, 444, -428, 444, -428, 444, -432, 444, -432, 444, -1188, 472, -1164, 444, -1188, 472, -1164, 444, -1188, 448, -1188, 448, -1188, 472, -1164, 448, -428, 444, -428, 444, -428, 444, -432, 440, -432, 444, -428, 444, -428, 444, -436, 444, -1188, 444, -1192, 444, -1188, 448, -1188, 444, -1188, 448, -1188, 444, -1188, 448, -1192, 444, -432, 440, -432, 444, -428, 444, -428, 444, -428, 444, -432, 444, -428, 444, -432, 444, -1192, 444, -1188, 448, -1188, 464, -1172, 444, -1188, 444, -1192, 444, -1188, 444, -1196, 444, -428, 444, -428, 444, -432, 444, -428, 444, -428, 444, -428, 444, -432, 444, -432, 444, -1188, 472, -1164, 444, -1192, 444, -1188, 444, -1192, 444, -1188, 448, -1188, 444, -1192, 448, -428, 444, -428, 444, -428, 444, -432, 444, -428, 444, -428, 444, -432, 440, -436, 444, -1188, 444, -1192, 444, -1188, 448, -1188, 444, -1188, 448, -1188, 444, -1192, 444, -1192, 444, -432, 444, -1188, 444, -1192, 444, -428, 444, -1188, 448, -428, 444, -1188, 448, -432, 444, -1188, 444, -432, 444, -428, 444, -1188, 448, -428, 444, -1188, 444, -428, 444, -1196, 444, -1188, 448, -428, 444, -428, 444, -432, 440, -1192, 444, -1188, 448, -1188, 444, -1192, 448, -428, 444, -1192, 444, -1188, 444, -1192, 444, -428, 444, -428, 444, -428, 444, -436, 444, -428, 444, -428, 444, -432, 444, -428, 444, -428, 444, -428, 444, -432, 440, -436, 444, -1188, 448, -1188, 444, -1192, 444, -1188, 444, -1192, 444, -1188, 464, -1172, 444, -1192, 448, -428, 444, -428, 444, -428, 444, -432, 440, -432, 444, -428, 444, -428, 444, -436, 440, -1192, 444, -1192, 444, -1188, 444, -1192, 444, -1188, 448, -1188, 444, -1188, 448, -1192, 444, -428, 444, -432, 444, -428, 444, -428, 444, -432, 440, -432, 444, -428, 444, -432, 444, -1192, 444, -1188, 448, -1188, 444, -1192, 444, -1188, 444, -1192, 444, -1188, 444, -1196, 468, -1164, 448, -1188, 444, -1192, 444, -1188, 444, -432, 440, -432, 444, -428, 444, -432, 444, -432, 440, -432, 444, -428, 444, -428, 444, -1192, 444, -1192, 444, -1188, 444, -1192, 448,

The command in this example contained the settings for Heat mode, 25 C degrees, Auto fan speed.

Analysing the pulse format

The text “Raw: (595)” is not a part of the code. It’s just part of the output from AnalysIR telling us type and length of the captured code. The code starts with 3280.
Positive numbers are pulses (38KHz PWM pulse) and negative numbers are pauses (silence). The number indicates the duration in microseconds (us).
If we look at the beginning of the code it differs a bit from the rest of the code.
3280 is a pulse with a length of 3280 us. It’s followed by -1704 which is a pause for 1704 us.
The code continues with 468 us pulse, 1168 us pause, 472 us pulse, 400 us pause, a new pulse and another pause and so on for the rest of the code. The code must always end with a pulse. The last pause wouldn’t be a pause if it didn’t have a pulse after it, would it?
The exact duration of the pulses and pauses varies a little bit between the recordings but not significantly. They do however differ a bit from the numbers in mroxanas blog. Our guess is that the relation between the lengths are more important than the actual lengths.

All the pulses are roughly the same length. Our average was around 450us.
The pauses are either long like 1168us or short like 400us.
Our averages were around 1180us and 400us so that’s the numbers we used in our tests and they worked well.
Here’s all the lengths:
First pulse: 3200 us
First pause: 1700 us
Pulse: 450 us
Long pause: 1180 us
Short pause: 400 us

The first pulse and pause is some start code.
The rest of the pauses are the bits that make out the data in the command. The pulses are just there to separate the pauses from eachother.
A long pause is binary one
A short pause is binary zero

The amount of bits is normally 296 (37 bytes). There seems to be some extra bits on the end if you use an alternate address setting on the remote control.

The data captured by the AnalysIR could be used as it is with the IRremote library’s sendRaw function. But to crack the protocol and gain higher flexibility when sending commands it’s neccessary to perform some deeper analysis. We must therefore conver all the raw data to bits.
We did this with a quick and dirty powershell script that takes the input from the AnalysIR sketch, strips out all the positive numbers and converts all the negative numbers to either 1 or 0 depending on how long they are. If it’s > -800 it’s a 0 and if it’s < -800  it’s a 1.

The code converted to binary:

10000000000010000000000000000010111111011111111100000000001100111100110011100101000110100010001011011101001001101101100100000000111111110000000011111111000000001111111100000000111111110000000011111111011010101001010110001111011100000000000011111111000000001111111100000000111111111111000000001111

Analyzing protocol data

To get a better overview of the data it would make sense to divide the data into bytes if that’s the way it’s organized.

       1        2        3        4        5        6        7        8        9       10       11       12       13       14       15       16       17       18       19       20       21       22       23       24       25       26       27       28       29       30       31       32       33       34       35       36       37
10000000 00001000 00000000 00000010 11111101 11111111 00000000 00110011 11001100 11100101 00011010 00100010 11011101 00100110 11011001 00000000 11111111 00000000 11111111 00000000 11111111 00000000 11111111 00000000 11111111 01101010 10010101 10001111 01110000 00000000 11111111 00000000 11111111 00000000 11111111 11110000 00001111

It’s quite obvious that the binary data makes out even bytes, just look at bytes 16-25.
It’s also obvious that every second byte starting with byte 5 has got all the bits from the previous byte inverted (bitwise NOT). So bits 4,6,8,10,12 etc are bytes with data while 5,7,9,11 etc are just parity bits.

To figure out what all the data is and where your settings are stored it’s neccessary to record several codes with only one change at a time and compare them to eachother so let’s compare the above example of 25 C temperature with 26 and 27 degrees:

            1        2        3        4        5        6        7        8        9       10       11       12       13       14       15       16       17       18       19       20       21       22       23       24       25       26       27       28       29       30       31       32       33       34       35       36       37
25C  10000000 00001000 00000000 00000010 11111101 11111111 00000000 00110011 11001100 11100101 00011010 00100010 11011101 00100110 11011001 00000000 11111111 00000000 11111111 00000000 11111111 00000000 11111111 00000000 11111111 01101010 10010101 10001111 01110000 00000000 11111111 00000000 11111111 00000000 11111111 11110000 00001111
26C  10000000 00001000 00000000 00000010 11111101 11111111 00000000 00110011 11001100 11100101 00011010 00100010 11011101 00010110 11101001 00000000 11111111 00000000 11111111 00000000 11111111 00000000 11111111 00000000 11111111 01101010 10010101 10001111 01110000 00000000 11111111 00000000 11111111 00000000 11111111 11110000 00001111
27C  10000000 00001000 00000000 00000010 11111101 11111111 00000000 00110011 11001100 11100101 00011010 00100010 11011101 00110110 11001001 00000000 11111111 00000000 11111111 00000000 11111111 00000000 11111111 00000000 11111111 01101010 10010101 10001111 01110000 00000000 11111111 00000000 11111111 00000000 11111111 11110000 00001111

There are only two bytes that changes – byte 14 and 15. Byte 15 is just parity so it’s byte 14 that contains the temperature.
25C: 00100110
26C: 00010110
27C: 00110110
If you know your binary numbers you will see that part of these bytes actually contain the temperature. The binary representation of 25 is 11001 but in the data from the remote it is written with the least significant bit first (LSB first) – 10011. in other words backwards.
After more tests it’s clear that the temperature is sent in byte 14 (and 15) no matter what mode the unit is operating in so that’s what byte 14 is used for.
The other bits of byte 14 has never changed in our tests so they are probably always 0.

We went through some basic settings to map out other functions and see what number correspond to certain codes but we have only been scratching the surface.

Mapped bytes

These are the bytes and bits that we know anything about today.

bytemap

We are quite sure about the green ones while we are just assuming that the orange ones are static.
The white bits are totally unknown or just indications which we haven’t investigated yet. Feel free to do so and let us know what you find in the comments.

Byte 12

Seems to be used differently by all remote control operations.
Combinations of bits seems to activate/deactivate different operations or modes but not all operations need byte 12 to work.

Observered variants
Operation Bits In combination with
Adding a timer 01000100 Minutes in bytes 18-24 and Timer type in byte 24 – bit 5 or 6
Removing a timer 00100100 Timer type in byte 24 – bit 5 or 6
Change fan speed 01000010 Byte 26
Change temperature 00100010 Byte 14
Plasma air purifying operation 10010010 Byte 28 – bit 8 = 0 (questionable)
Mold monitor operation 11010010 Byte 34 – bit 7 = 1
Internal cleaning operation 11110010 Byte 34 – bit 4 = 1
Ionized mist operation 00010110 Byte 30 – bit 1 = 1
Sleep operation 11010110 Byte 32 – bit 5 = 1
Toggle(?) vertical air deflector movement 10000001
Adjust horizontal air deflectors 00110001 Byte 10?
Air quality monitor operation 01000011 Byte 34 – bit 3 = 1

Some of these operations like fan and temperature don’t need a specific code in this byte because they are all being set every time a code is sent. Is the same true for mist, sleep, monitoring modes and horizontal deflectors etc?
We have not tried to replicate all of these operations.
Must investigate further.

Byte 13

Bitwise NOT of Byte 12.

Byte 14

Temperature
Bits 1-2: Always 0
Bits 3-7: Room temperature setting in Celsius. Possible values:  16 to 32 for most modes, 10 to 32 for dehumidify.
Bit 8: Always 0

Bit 3 is LSB and bit 7 MSB so 22 degrees would be written 01101
Fill out with the other bits and you get 00011010.

Byte 15

Bitwise NOT of Byte 14.
At 22 degrees it would be 11100101

Byte 16

Possibly related to timers.

Byte 18+20

These bytes are used together to set a time for an OFF TIMER
The time is specified in minutes from now and stored as an LSB first 11 or 12-bit number starting at Byte 18, Bit 5 and ending in Byte 20, Bit 7 (or 8?).

Byte 18, Bit 1-4: Seems to always be 0000
Byte 18, Bit 5-8 (5 is LSB)
Byte 20, Bit 1-7 (7 is MSB)
Byte 20, Bit 8: Possibly bit 12 (MSB bit) but most likely always 0 since no valid numbers need that man bits.

Example

To specify 600 minutes.
600 binary = 1001011000
600 binary LSB first 0001101001
Byte 18 + 20 = xxxx0001 10100100

Byte 19+21

Bitwise NOT of bytes 18 and 20

Bytes 22+24

These bytes are used together to set a time for an ON TIMER
The time is specified in minutes from now and stored as an LSB first 11 or 12-bit number starting at Byte 22, Bit 1 and ending in Byte 24, Bit 3 (or 4?).
Two bits in byte 24 are also used to activate on timer or off timer or both (on/off timer).

Byte 22, Bit 1-8 (bit 1 is LSB)
Byte 24, Bit 1-3 (bit 3 is MSB)
Byte 24, Bit 4: Possibly bit 12 (MSB bit) but most likely always 0 since no valid numbers need that man bits.
Byte 24, Bit 5: Activate off timer when set to 1
Byte 24, Bit 6: Activate on timer when set to 1

Example

To specify 600 minutes.
600 binary = 1001011000
600 binary LSB first 0001101001
Byte 22 + 24 = 00011010 0100xxxx

Byte 23+25

Bitwise NOT of bytes 22 and 24

Byte 26

Modes + Fan speed
Bits 1-4: Mode setting. Possible values: Not fully known
Bits 5-7: Fan speed. Possible values: 1 (silent) to 5 (automatic)
Bit 8: Always 0

Modes

All 16 binary combinations listed even though all aren’t known and some may not be valid.

Setting No. Bit 1 Bit 2 Bit 3 Bit 4 Mode
0 0 0 0 0 ?
1 1 0 0 0 ?
2 0 1 0 0 ?
3 1 1 0 0 Cool
4 0 0 1 0 Dry Cool
5 1 0 1 0 Dehumidify
6 0 1 1 0 Heat
7 1 1 1 0 Automatic Operation
8 0 0 0 1 ?
9 1 0 0 1 Auto Dehumidifying
10 0 1 0 1 Quick Laundry
11 1 1 0 1 ?
12 0 0 1 1 Condensation Control
13 1 0 1 1 ?
14 0 1 1 1 ?
15 1 1 1 1 ?
Fan speed
Setting No. Bit 5 Bit 6 Bit 7 Fan Speed
1 1 0 0 Silent
2 0 1 0 Low
3 1 1 0 Med
4 0 0 1 Hi
5 1 0 1 Auto
Byte 27

Bitwise NOT of Byte 26.
If Byte 26 is set to Mode=Cool and Fan=Hi (11000010), Byte 27 would have to be 00111101.

Byte 28

Power On/Off + Sleep timer(?)
Partly unknown.

Bit 1-4: Has always been 1000 in our tests.
Bit 5: Turn unit on (1) or off (0). Should always be 1 when changing other settings.
Bit 6-7: Has always been 11 in our tests.
Bit 8: Function is not investigated but turns to 0 when sleep timer is activated. Otherwise 1.

Examples

10001111: Power on unit or keep unit on when changing settings
10000111: Power off.

Byte 29

Bitwise NOT of Byte 28

Byte 30

Bit 5-6: Set to 11 to enable Powerful Operation (not tested)

Byte 31

Bitwise NOT of Byte 30

Byte 36

Bit 1-4: Has always been 1111 in our tests.
Bit 5-8: Humidity. Possible values: 3 (40%) to 9 (70%)

Setting No. Bit 5 Bit 6 Bit 7 Bit 8 Humidity
3 1 1 0 0 40%
4 0 0 1 0 45%
5 1 0 1 0 50%
6 0 1 1 0 55%
7 1 1 1 0 60%
8 0 0 0 1 65%
9 1 0 0 1 70%
Byte 37

Bitwise NOT of Byte 36

More bytes and bits will be added if we find any. If you have any additions or corrections please leave a comment.

Controlling the unit using Arduino

Now that we have a few known commands it’s possible to control the individual functions of the unit.
We need to send the full 37 bytes every time so it’s necessary to have a complete default command to fill out the areas that we don’t know much about. We can then replace selected parts of that default command to create a full custom command.

We went with one of the examples above as a starting point.
Heat, 25 degrees, Fan=Auto.

10000000000010000000000000000010111111011111111100000000001100111100110011100101000110100010001011011101001001101101100100000000111111110000000011111111000000001111111100000000111111110000000011111111011010101001010110001111011100000000000011111111000000001111111100000000111111111111000000001111

We put all the bits from the default command into an array. Then we replace the necessary bits with the values we want. If we want to change the temperature we need the binary LSB first representation of the temperature. That’s five bits.
We then replace the bits with offset 106-110 in our array with the five bits representing the new temperature.
If everything else in the default command is ok we can send the command now and the temperature will change.

Sending the command means doing a lot of pulsing at 38Khz. A pulse can be sent from arduino by toggling a pin with an IR LED between HIGH and LOW every 26us.
A function like this can do that and takes the length of the pulse as an argument:

void sendPulse(int pulseLength){
  int IR_on = 0;
  long startMicros;
  startMicros = micros();
  while (micros() < (startMicros + pulseLength)){
    // sending 38 KHz pulse
    if (IR_on == 0) {
      IR_on = 1;
    }
    else {
      IR_on = 0;
    }
    digitalWrite(IRPIN, IR_on);
    delayMicroseconds(26);
  }
  // turn off IR after pulse is complete
  digitalWrite(IRPIN, LOW);
}

According to what we learned from our analysis of the protocol we would have to begin the command with a special pulse and a special pause, then standard pulses and delays for either 0 or 1.
Literally:

sendPulse(3200);
delayMicroseconds(1700);
sendPulse(450);
delayMicroseconds(1180);
sendPulse(450);
delayMicroseconds(400);
sendPulse(450);
delayMicroseconds(400);
sendPulse(450);
delayMicroseconds(400);
...
<hundreds of bits>
...
sendPulse(450);
delayMicroseconds(1180);
sendPulse(450);
delayMicroseconds(1180);
sendPulse(450);

Of course you wouldn’t code it like this.
Instead you loop through an array with all the bits that needs to be sent as mentioned earlier and you just send the special pulses using a teqnique such as the example above.

Download a complete example sketch for sending a command here.
SendHitachiCode.ino

Here’s another sketch that takes commands from the serial monitor on the Arduino. It converts the supplied values and applies them to the right positions in the command and then sends the command.
HitachiACRemote.ino

Categories: Arduino, Projects

Gather HP iLO information using PowerShell

2014-03-11 10 comments

Please begin by reading my previous post where I show how to retrieve physical hard disk information such as model numbers and firmware versions using the HP Insight Management WBEM providers.

A few days ago, as HP published an advisory regarding firmware of their Integrated Lights-Out (iLO) management controllers I wanted a way to collect this information from a number of servers. I created another CmdLet to retrieve information from two associated classes.
Namespace: root\hpq
Classes: HP_MPFirmware and HP_ManagementProcessor

For full details about the properties in these classes as well as the rest of the HP WBEM classes, download the latest version of the PDF document HP Insight Management WBEM Providers for Microsoft Windows Data Sheet

The Get-HPiLOInformation function

Update: Improved cmdlets available here

function Get-HPiLOInformation
{
    <#
    .SYNOPSIS
    Retrieves iLO management controller firmware information
    for HP servers.

    .DESCRIPTION
    The Get-HPiLOInformation function works through WMI and requires
    that the HP Insight Management WBEM Providers are installed on
    the server that is being quiered.

    .PARAMETER Computername
    The HP server for which the iLO firmware info should be listed.
    This parameter is optional and if the parameter isn't specified
    the command defaults to local machine.
    First positional parameter.

    .EXAMPLE
    Get-HPiLOInformation
    Lists iLO firmware information for the local machine

    .EXAMPLE
    Get-HPiLOInformation SRV-HP-A
    Lists iLO firmware information for server SRV-HP-A

    .EXAMPLE
    "SRV-HP-A", "SRV-HP-B", "SRV-HP-C" | Get-HPiLOInformation
    Lists iLO firmware information for three servers

    #>
    [CmdletBinding(SupportsShouldProcess=$true)]
    Param(
    [Parameter(Mandatory=$false, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position = 1)][string]$Computername=$env:computername
    )

    Process{

        if ($pscmdlet.ShouldProcess("Retrieve iLO information from server " +$Computername)){
            $MpFirmwares =  Get-WmiObject -Computername $ComputerName -Namespace root\hpq -Query "select * from HP_MPFirmware"
            ForEach ($fw in $MpFirmwares){
                $Mp = Get-WmiObject -Computername $ComputerName -Namespace root\hpq -Query ("ASSOCIATORS OF {HP_MPFirmware.InstanceID='" + $fw.InstanceID + "'} WHERE AssocClass=HP_MPInstalledFirmwareIdentity")

                $OutObject = New-Object System.Object
                $OutObject | Add-Member -type NoteProperty -name ComputerName -value $ComputerName
                $OutObject | Add-Member -type NoteProperty -name ControllerName -value $fw.Name

                Switch ($Mp.HealthState){
                    5 {$stat = "OK"; break}
                    10 {$stat = "Degraded/Warning"; break}
                    20 {$stat = "Major Failure"; break}
                    default {$stat = "Unknown"}
                }
                $OutObject | Add-Member -type NoteProperty -name HealthState -value $stat

                $OutObject | Add-Member -type NoteProperty -name UniqueIdentifier -value $Mp.UniqueIdentifier.Trim()
                $OutObject | Add-Member -type NoteProperty -name Hostname -value $Mp.Hostname
                $OutObject | Add-Member -type NoteProperty -name IPAddress -value $Mp.IPAddress

                Switch ($Mp.NICCondition){
                    2 {$stat = "OK"; break}
                    3 {$stat = "Disabled"; break}
                    4 {$stat = "Not in use"; break}
                    5 {$stat = "Disconnected"; break}
                    6 {$stat = "Failed"; break}
                    default {$stat = "Unknown"}
                }
                $OutObject | Add-Member -type NoteProperty -name NICCondition -value $stat

                $OutObject | Add-Member -type NoteProperty -name FirmwareVersion -value $fw.VersionString
                $OutObject | Add-Member -type NoteProperty -name ReleaseDate -value ($fw.ConvertToDateTime($fw.ReleaseDate))

                Write-Output $OutObject
            }
        }
    }
}

Download hpilo.ps1 here

Example of the output

PS C:\Windows\system32> Import-Module C:\MyPath\hpilo.ps1
PS C:\Windows\system32> Get-HPiLOInformation SRV-HP-A

ComputerName : SRV-HP-A
ControllerName : Integrated Lights Out 4 (iLO4)
HealthState : OK
UniqueIdentifier : ILOCZ123456AB
Hostname : SRV-HP-A-ILO
IPAddress : 192.168.0.201
NICCondition : OK
FirmwareVersion : 1.40
ReleaseDate : 2014-01-14 02:00:00

PS C:\Windows\system32
Categories: Computing, Windows

Gather HP server disk information using PowerShell

2013-05-08 6 comments

I frequently find a need to quickly gather information about the hard drives in my HP Proliant servers. Sometimes I just need to find the model numbers but sometimes I also need information such as serial numbers and firmware versions.
This information is useful when HP releases an urgent firmware upgrade advisory or launches a disk replacement program of which both seem to be quite common lately.

All the needed information is available through WMI on servers that have the HP Insight Management WBEM Providers installed.

Namespace: root\hpq
Classes: HPSA_DiskDrive and it’s associated classes

I wrote the following Powershell function that creates a command that gathers information from servers and returns them as an object that can be sorted, filtered and exported the way you need just as any powershell object.

Update: Improved cmdlets available here

function Get-HPArrayDisks
{
    <#
    .SYNOPSIS
    Retrieves physical hard disk information for HP servers.

    .DESCRIPTION
    The Get-HPArrayDisks function works through WMI and requires
    that the HP Insight Management WBEM Providers are installed on
    the server that is being quiered.

    .PARAMETER Computername
    The HP server for which the disks should be listed.
    This parameter is optional and if the parameter isn't specified
    the command defaults to local machine.
    First positional parameter.

    .EXAMPLE
    Get-HPArrayDisks
    Lists physical disk information for the local machine

    .EXAMPLE
    Get-HPArrayDisks SRV-HP-A
    Lists physical disk information for server SRV-HP-A

    .EXAMPLE
    "SRV-HP-A", "SRV-HP-B", "SRV-HP-C" | Get-HPArrayDisks
    Lists physical disk information for three servers

    #>
    [CmdletBinding(SupportsShouldProcess=$true)]
    Param(
    [Parameter(Mandatory=$false, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position = 1)][string]$Computername=$env:computername
    )

    Process{

        if ($pscmdlet.ShouldProcess("List disks on server " +$Computername)){
            $diskdrives =  Get-WmiObject -Computername $ComputerName -Namespace root\hpq -Query "select * from HPSA_DiskDrive"
            ForEach ($disk in $diskdrives){
                $OutObject = New-Object System.Object
                $OutObject | Add-Member -type NoteProperty -name ComputerName -value $ComputerName
                $OutObject | Add-Member -type NoteProperty -name Slot -value $disk.ElementName
                $OutObject | Add-Member -type NoteProperty -name Interface -value $disk.Description
                $OutObject | Add-Member -type NoteProperty -name RotationalSpeed -value $disk.DriveRotationalSpeed

                $drivePhys = Get-WmiObject -Computername $ComputerName -Namespace root\hpq -Query ("ASSOCIATORS OF {HPSA_DiskDrive.CreationClassName='HPSA_DiskDrive',DeviceID='" + $disk.DeviceID + "',SystemCreationClassName='" + $disk.SystemCreationClassName + "',SystemName='" + $disk.SystemName + "'} WHERE AssocClass=HPSA_DiskPhysicalPackageDiskDrive")
                $OutObject | Add-Member -type NoteProperty -name Model -value $drivePhys.Model
                $OutObject | Add-Member -type NoteProperty -name SerialNumber -value $drivePhys.SerialNumber.trim()

                $driveFW = Get-WmiObject -Computername $ComputerName -Namespace root\hpq -Query ("ASSOCIATORS OF {HPSA_DiskDrive.CreationClassName='HPSA_DiskDrive',DeviceID='" + $disk.DeviceID + "',SystemCreationClassName='" + $disk.SystemCreationClassName + "',SystemName='" + $disk.SystemName + "'} WHERE AssocClass=HPSA_DiskDriveDiskDriveFirmware")
                $OutObject | Add-Member -type NoteProperty -name FirmwareVersion -value $driveFW.VersionString.trim()

                $driveStorage = Get-WmiObject -Computername $ComputerName -Namespace root\hpq -Query ("ASSOCIATORS OF {HPSA_DiskDrive.CreationClassName='HPSA_DiskDrive',DeviceID='" + $disk.DeviceID + "',SystemCreationClassName='" + $disk.SystemCreationClassName + "',SystemName='" + $disk.SystemName + "'} WHERE AssocClass=HPSA_DiskDriveStorageExtent")
                $OutObject | Add-Member -type NoteProperty -name SizeInGigabytes -value ([math]::round(($driveStorage.BlockSize * $driveStorage.NumberOfBlocks) / 1000000000))
                $OutObject | Add-Member -type NoteProperty -name PowerOnHours -value $driveStorage.TotalPowerOnHours

                Write-Output $OutObject
            }
        }
    }
}

Download hpdisks.ps1 and import it in your powershell session using the command

Import-Module hpdisks.ps1

When you have imported the module you can get help about it’s command just like you would with any other powershell command.

Get-Help Get-HPArrayDisks -detailed

Whatever you pipe into the Get-HPArrayDisks command will be treated as a server name and it will attempt to gather HP disk information from the server.
You can pipe names from the commnd line, from other commands or from text files using the Get-Contents command. Some quick examples:

Get-HPArrayDisks myservername

"myserver1","myserver2" | Get-HPArrayDisks | ft computername, slot, model, serialnumber

Get-Content allmyservers.txt | Sort-Object | Get-HPArrayDisks | Export-Csv -path myserverdisks.csv -NoTypeInformation

You may also want to read
Gather HP iLO information using PowerShell

Categories: Computing, Windows

Using Rotary Encoders with Arduino

2012-11-01 8 comments

Rot enc

Introduction

There seems to be a lot of confusion among Arduino beginners about how rotary encoders work and how you best use them with Arduino.

I will try to explain a little bit and show some examples to get you started. The example circuit and the code should be enough to get you started if you don’t want to read the other mumbo jumbo.

What is a rotary encoder?

A rotary encoder is electromechanical component with a shaft. Shaft rotation is recorded and converted to electrical pulses that tell in which direction the shaft is rotating. The shaft has unlimited 360 degree rotation.

A rotary encoder can tell you:

  • That the shaft is rotating
  • How much it is rotating
  • In which direction it is rotating

A rotary encoder can NOT tell you:

  • The position or the orientation of the shaft (knobs with indicators are useless)

Protocol

I’m not going to get into the inner workings of rotary encoders but let’s mention how a simple rotary encoder commuinicate.

There are two output pins (called A and B) that are used to for reading rotation and a third pin that normally connects to GND.
When you turn the encoder, switches inside the encoder opens and closes to turn the outputs HIGH or LOW.

The rotary encoders “speak” gray code which means that the encoder pins are cycling through a predetermined pattern of HIGH and LOW signals.
When you turn the shaft of the encoder clockwise the signal on the encoder pins loops through a pattern like this:

A B
0 0
1 0
1 1
0 1

If we can detect that the pins are changing we know that the shaft is rotating. How often the pulses change tells us how fast it’s turning. How many times it has changed tells us how far it has been turned etc.
When you turn the shaft counter-clockwise it loops through the sequence backwards and that’s how we know in which direction it’s rotating.
Most shaft encoders have fixed stops or “stability positions” so that the shaft stops or clicks at every 0pen-0pen or closed-closed position or both.
Your datasheet will reveal which type you have. There will be a pulse diagram in of the pulses at clockwise operation that looks something like one of the below pictures. The dotted lines indicate shaft stops.

Stops at every closed position

Stops at both closed and open position

Bounce

Cheap encoders are known to cause a lot of contact bounce so you will need to debounce the signal from the encoders. We will use interrupts on the Arduino for detecting encoder rotation so it’s easier to debounce the encoder with hardware and get nice clean pulses than to try and debounce using software delay.

I have tried some variants and settled with 47nF ceramic capacitors and Schmitt Triggers on the outputs. I have also connected the shield on my encoders to ground through another 47nF ceramic capacitor.

Example circuit

This is how to debounce and connect an encoder to the Arduino:

Example circuit with debounced rotary encoder connected to Arduino

I connect encoder output A to D2 on the Arduino because D2 is an interrupt pin (interrupt 0) which we will use to detect rotation.
Output B can go to any digital pin. I use pin 4 in the example.

If you want to connect another encoder to the same Arduino, use pin D3 for output A on that encoder and enable interrupt 1.

I you have an Arduino Mega you can use four additional interrupts on pins D18, D19, D20, D21.

Arduino sketch

This is an example that uses one interrupt to detect rotation on a rotary encoder which only stops when it’s in closed position.
If you have an encoder that stops at both closed and open you will have to turn your encoder two clicks to register a turn. Correct this by changing the interrupt type from RISING to CHANGE sol that an interrupt is triggered on every change.

int pinA = 2; //Encoder pin A connects to interrupt 0 (D2)
int pinB = 4; //Encoder pin B connects to D4
int iValue = 0; //A variable that will be increased or decreased
                //when we turn the encoder

void setup() {
  Serial.begin(9600);
  
  pinMode(pinA, INPUT);  
  pinMode(pinB, INPUT);
  
  // Enable interrupt on encoder pin A
  // Trigger at RISING if your encoder stops (clicks) only at high pulse
  // Trigger at CHANGE if your encoder stops (clicks) at both high and low
  // positions or if it has no stops
  attachInterrupt(0, encoderClick, RISING);
}


void loop() {
  // continuously print the value to see how it changes
  Serial.println(iValue);
  delay(200);
}


void encoderClick(){
  // encoder must have turned one click because interrupt 0 was triggered
  // read value from both encoder pins
  int valA = digitalRead(pinA);
  int valB = digitalRead(pinB);
  
  // compare pins to determine in which direction encoder was turned
  if (valA != valB){
      // pinA just changed but pinB had not yet changed
      // Direction must be clockwise if A changes before B
      iValue++;
  }
  else{
      // pinA just changed and pinB had already done so.
      // Direction must be counter-clockwise if B changes before A
      iValue--;
  }
}

Download the sketch here

Categories: Arduino

Arduino based remote control for electric door

2012-10-14 4 comments

I recently built a replacement remote control system for an electric garage door after the old remote had given up for the babillionth time.
I’m sure the old one would have been possible to repair once again but it was 35 years old and not much fun.

Old receiver and transmitter

Pictures from left to right:

  1. The front of the old receiver with an indoor open/close button.
  2. Inside of the receiver. Nice and clean and very analog electronic fossil.
  3. The guts from the old transmitter. The case that this used to sit in was removed and reused for the new transmitter.
  4. Backside of the old receiver. The label reads “Chambron Radio Control Model C-2216”. There’s also a letter to Mr. Serviceman.
    Who knows anything about this thing?

The motor to the door is controlled by shorting two cables and thereby closing a circuit. A short pulse is enough to start the motor. If the door is closed it will open. If it’s already open, the door will close. If the motor is moving when the pulse arrives it will change direction.

The new solution

433MHz transmitter (left) and receiver (right)

I wanted a new solution that would be a bit more secure and hopefully have the same range as the old one had and I wanted to base it on an ATmega328P with an Arduino core and some really cheap 433Mhz ASK modulated RX/TX modules that can be found everywhere on eBay.

I have used these RF modules before and know they have a decent range and can penetrate doors, windows and even walls in some cases. They are also easy to interface with using the VirtualWire library for Arduino. The downside is that they only work in one direction.

Even if it wasn’t really necessary in this case I wanted to implement some kind of security or obfuscation of the commands sent over the air. This is something of a challenge with a system that only communicates in one direction since it’s not possible to use a challenge/response based protocol and the Arduino doesn’t have storage enough to store predefined passcode sequenced.
This was what I wanted:

  • Use one time passcodes so that simple sniffing wouldn’t be enough to grant access forever
  • Not have to store the passcode sequence in advance
  • Generate passcodes that don’t seem to follow a clear pattern to complicate analysis of the commands

The protocol I ended up with works like this:

  • The receiver and transmitter are paired to use a sequence of numbers starting at a large random number that is decided by the transmitter. The number is sent to the receiver during the pairing process which more or less is a one time operation.
  • When the transmitter wants to send a open/close command to the door it increases the number by one and hashes the number using MD5
  • The receiver knows which number it expects and when it receives a hash from the transmitter it hashes the expected number and compares the resulting hash with the received hash. If the hash is correct it sends a pulse to the door so that it will be opened or closed. The next expected passcode is simply the last passcode +1.
  • If the hashes didn’t match it increases the expected number one by one and creates new hashes to compare with up to fifty times to allow for missed passcodes that might have been sent when the transmitter was out of range or similar. This gives us a sliding window of 50 valid passcodes. As soon as a matching passcode is found, the receiver is synced with the number received and a pulse is sent to the door.
  • The current numbers are stored in the ATmega EEPROM in both transmitter and receiver.

Hardware

The new transmitter and receiver waiting for installation

I’m using ATmega328P (DIP-28) for both transmitter and receiver. I would probably have used an ATtiny for the transmitter to try and reduce size if it wasn’t for the MD5 library that adds a whopping 12KB to the  binary sketch size making the total sizes around 18KB for both receiver and transmitter.

Transmitter

Since I couldn’t find a suitable pocket size case for the transmitter and a good matching push button I reused the old one. The green LED to the left of the battery pack was added for troubleshooting reasons during installation but I never drilled a hole in the case for that LED due to lack of space.
The button at the top of the PCB is the open/close button. There’s another button on the back side of the PCB that is used during pairing.
The blue cable that is routed from the RF module and around the PCB is the antenna which is a piece of wire that is cut to a quarter of the wavelength equaling 17.3cm.
34.5cm or 69.1cm would also have been OK if there was space enough in the box but looping the antenna round and round in several loops close to each other would not do much good.
The new transmitter resting in the case from the old transmitter (lid open)
The ATmega in the transmitter is running on the internal oscillator at 8MHz to allow the supply voltage to drop to 3.0V. The 16MHz external crystal in the picture is still there but was only used during prototyping. I’m also disabling brownout detection on the ATmega for maximum power savings during power down. The fuses I’m using for setting the clock source to internal oscillator @ 8MHz and disable brownout detection are:
Low Fuses: E2
High Fuses: DA
Extended Fuses: 07

The board definition I put in boards.txt is:

##############################################################
328_8.name=ATmega328, 8MHz Internal OSC, BOD disabled
328_8.upload.protocol=arduino
328_8.upload.maximum_size=30720
328_8.upload.speed=57600
328_8.bootloader.low_fuses=0xE2
328_8.bootloader.high_fuses=0xDA
328_8.bootloader.extended_fuses=0x07
328_8.bootloader.path=atmega
328_8.bootloader.file=ATmegaBOOT_168_atmega328_pro_8MHz.hex
328_8.bootloader.unlock_bits=0x3F
328_8.bootloader.lock_bits=0x0F
328_8.build.mcu=atmega328p
328_8.build.f_cpu=8000000L
328_8.build.core=arduino
328_8.build.variant=standard
##############################################################

This configuration makes it possible to use a bootloader if desired but I upload the sketch to the chip using an ISP programmer so I don’t have a need for a bootloader in this case.
For other applications using 8MHz internal oscillator, I have always used the ATmegaBOOT bootloader because I’ve not had any luck compiling the Optiboot for this. If someone has a Makefile that is generating a working Optiboot image for 8MHz internal, please let me know in the comments.

Receiver

I got rid of the old receiver case because it was made of thick metal and I was afraid that it could affect the reception in a negative way but it would probably have been OK due to the external antenna. There are plenty of boxes suitable for the transmitter but I settled with a minimal, cheap plastic box for electric installations. I should have picked a bigger one because this was a pretty tight fit.
The connector on the right side is the DC plug for the power supply.
To the left is an LED that flashes during pairing and is lit during reception of data. The button on the same side as the LED is the pairing button.

The antenna which is rolled up outside the box in this picture should normally be stretched out. It consists of 69.1 cm of wire soldered to the antenna connection on the RF module.

The new receiver box with lid, sides and terminals removed

Motor connection

I send the pulses for the motor by running the two wires from the motor through a relay inside the receiver. I pull the relay for a short time using an output on the Arduino whenever a matching hash has been received.
I also added an external momentary push button mounted on the wall that shorts the same two wires so that the door can be opened and closed from the inside without using the remote control.

Receiver installed in garage with indoor open/close momentary button attached

Performance

How well does this solution work?

Range

50 metres (with the transmitter in a car, new batteries in the transmitter and the receive inside the closed garage door)
This is more than enough and just as good as the old system ever was.

Power consumption: Receiver

Approx. 30mA @ 5V
I haven’t done anything to reduce the power consumption on the receiver since it will be powered by a DC adapter.

Power consumption: Transmitter

The transmitter runs straight from three AA batteries that should (until depleted) keep the voltage over  3.0V at all times which is what the RF transmitter module needs to work properly. The maximum 4.5V is also perfectly fine for both RF module and ATmega.
Current during transmission (basically as long as the button is pressed) is ~25mA @ 4.5V
During powerdown which is the normal condition when no button is pressed, the current drops to 0.1uA
This is as low as it gets with an ATmega328P and to achieve this brownout detection has to be disabled.

Possible future improvements

  • Add possibility to use more than one transmitter.
  • Prevent brute force attacks by adding growing delays after incorrect codes
  • Etch custom PCBs, possibly using SMT components for transmitter
  • Add more decoupling capacitors, at least for the receiver.
  • Shrink the transmitter by creating better and smaller case and PCB for the transmitter
  • Fix bugs
  • Well… let’s see how it works

References

Code

Download both sketches and all libraries in one zip file: Code

Schematics

The schemattics for both units in PNG format: Transmitter and Receiver

Video

Categories: Arduino, Projects
Follow

Get every new post delivered to your Inbox.