Your thinking is still too low-level. You're looking for a better way to say things like "What's the value of O2 detected by O2 Sensor #2?" But why do you need to know that value? What are you going to do on the basis of the value?
If you just want a wrapper that's a bit less cumbersome, sure, write that. But if you want a genuine domain-specific language, you need to start by thinking much more high-level. You also need to consider making objects that are more capable.
Let's say you need to show an alert if the O2 level is too low. Simple:
if (new Controller().O2Sensors[1].Value < 30)
MessageBox.Show("The canary has died.");
Simple, but not good. To get the most flexible OO design, you should be telling objects what to do rather than querying them:
new Controller().ShowAlertIfMainOxygenLevelTooLow();
Then the Controller itself knows which oxygen sensor is the main one, and it knows what "too low" means.
But what if "too low" differs by environment? Maybe your controller might be used on a space station, and the O2 environment is richer, and even a small drop indicates trouble. In that case you'd need to construct your Controller with an appropriate strategy, something like:
public class Controller
{
public Controller(IOxygenLevelDetector oxygenLevelDetector)
{
[...]
}
}
Your IOxygenLevelDetector interface might have a method that takes the O2 sensor, reads the current O2 level, and returns a bool indicating whether the level is too low, or whether the level is in a success or failure state...whatever makes the most sense to you. You'd construct your Controller with the appropriate environment:
new Controller(new SpaceStation())
or
new Controller(new RoomOnEarth())
Of course, at some point you're still reading the oxygen level and then doing something. How do you know when it's the wrong place to do that? A good rule of thumb is to minimize dots. Something like this
new ServiceBoard().Controllers[5].O2Sensors[1].OxygenGauge.Value
is too many dots. The ServiceBoard has too much visibility into the internals of a lot of other objects. All it should do is go one level: Tell a Controller to do something, and wait for the reply. The Controller, in turn, should tell an O2Sensor to do something, and should wait for the reply. In this way, even when you have to make changes, you avoid having them ripple through the entire program.