1: using System;
2: using Microsoft.Win32;
3:
4: namespace HomeServer.Notifications
5: {
6: /// <summary>
7: /// Manipulate the lights on an HP MediaSmart Windows Home Server
8: /// </summary>
9: public class Lights : IDisposable
10: {
11: // Registry LocalMachine key path where the values are stored (as DWORD values)
12: private const string _key = @"SOFTWARE\Hewlett-Packard\HP MediaSmart Server\LEDs";
13:
14: // The registry key that we'll work against
15: private RegistryKey _leds;
16:
17: // Whether or not the key is currently opened for writing
18: private bool _isWriting;
19:
20: /// <summary>
21: /// Gets whether the lights are available on the current system.
22: /// </summary>
23: /// <remarks>
24: /// When unavailable, any attempt to read or write values will
25: /// result in an InvalidOperationException.
26: /// </remarks>
27: public bool Available
28: {
29: get
30: {
31: // Try to open the registry key for reading
32: OpenForReading();
33:
34: // If we found the key, then indicate that the lights are available
35: return _leds != null;
36: }
37: }
38:
39: /// <summary>
40: /// Gets or Sets the native value for the brightness
41: /// </summary>
42: private object BrightnessValue
43: {
44: get
45: {
46: return Read("Brightness");
47: }
48: set
49: {
50: Write("Brightness", value);
51: }
52: }
53:
54: /// <summary>
55: /// Gets or Sets the native value for the theme
56: /// </summary>
57: private object ThemeValue
58: {
59: get
60: {
61: return Read("Theme");
62: }
63: set
64: {
65: Write("Theme", value);
66: }
67: }
68:
69: /// <summary>
70: /// The current brightness value: 0-9
71: /// </summary>
72: public Int32 CurrentBrightness
73: {
74: get { return Convert.ToInt32(BrightnessValue); }
75: set
76: {
77: if (value < 0 || value > 9)
78: {
79: throw new ArgumentOutOfRangeException("Brightness values must be 0-9");
80: }
81:
82: BrightnessValue = value;
83: }
84: }
85:
86: /// <summary>
87: /// The current Theme of the lights
88: /// </summary>
89: public Theme CurrentTheme
90: {
91: get { return (Theme)Convert.ToInt32(ThemeValue); }
92: set { ThemeValue = (Int32)value; }
93: }
94:
95: /// <summary>
96: /// Open the registry key for reading
97: /// </summary>
98: /// <remarks>
99: /// Store the open key in a member variable, and don't re-open
100: /// the key if it's already open
101: /// </remarks>
102: private void OpenForReading()
103: {
104: if (_leds == null)
105: {
106: _leds = Registry.LocalMachine.OpenSubKey(_key, false);
107: }
108: }
109:
110: /// <summary>
111: /// Read a native value from the registry key
112: /// </summary>
113: /// <remarks>
114: /// Will ensure the lights are available and then open the key
115: /// for reading in order to get the value
116: /// </remarks>
117: /// <param name="valueName"></param>
118: /// <returns></returns>
119: private object Read(string valueName)
120: {
121: EnsureAvailable();
122: OpenForReading();
123:
124: return _leds.GetValue(valueName);
125: }
126:
127: /// <summary>
128: /// Write a native key value
129: /// </summary>
130: /// <remarks>
131: /// Will ensure the lights are available and that the key
132: /// is presently opened for writing. If it was previously
133: /// opened for reading, it will be closed and then re-opened
134: /// for writing.
135: /// </remarks>
136: /// <param name="valueName"></param>
137: /// <param name="value"></param>
138: private void Write(string valueName, object value)
139: {
140: // Make sure the lights are available
141: EnsureAvailable();
142:
143: // If we already had the key open for reading, close it
144: if (_leds != null && !_isWriting)
145: {
146: _leds.Close();
147: _leds = null;
148: }
149:
150: // If we don't have the key open, open it for writing
151: if (_leds == null)
152: {
153: _leds = Registry.LocalMachine.OpenSubKey(_key, true);
154: _isWriting = true;
155: }
156:
157: // Set the value and flush to disk
158: _leds.SetValue(valueName, value);
159: _leds.Flush();
160: }
161:
162: /// <summary>
163: /// Ensure the lights are available. When unavailable, throw
164: /// InvalidOperationException.
165: /// </summary>
166: private void EnsureAvailable()
167: {
168: if (!Available)
169: {
170: throw new InvalidOperationException("Lights not available. Maybe this isn't a MediaSmart server.");
171: }
172: }
173:
174: /// <summary>
175: /// Implement IDisposable, properly disposing of resources
176: /// </summary>
177: public void Dispose()
178: {
179: // Close the registry key if still open
180: if (_leds != null)
181: {
182: _leds.Close();
183: _leds = null;
184: }
185: }
186:
187: /// <summary>
188: /// Offer some helper values for brightness, allowing for consistent usage
189: /// </summary>
190: /// <remarks>
191: /// This is a static class with these readonly properties instead of an enum
192: /// because an enum would have required constant casting.
193: /// </remarks>
194: public static class Brightness
195: {
196: public static readonly Int32 Off = 0;
197: public static readonly Int32 Low = 1;
198: public static readonly Int32 MediumLow = 3;
199: public static readonly Int32 Medium = 4;
200: public static readonly Int32 MediumHigh = 5;
201: public static readonly Int32 High = 7;
202: public static readonly Int32 Max = 9;
203: }
204:
205: /// <summary>
206: /// The list of themes supported by the server
207: /// </summary>
208: public enum Theme
209: {
210: Default = 0,
211: HolidayLights = 1,
212: DescendingChaserBlue = 2,
213: AscendingChaserBlue = 3,
214: DescendingChaserPurple = 4,
215: AscendingChaserPurple = 5,
216: DescendingChaserRed = 6,
217: AscendingChaserRed = 7,
218: PulsingColors = 8,
219: PulsingBlue = 9,
220: PulsingPurple = 10,