AI is all the rage nowadays and it’s abundantly clear that it’s not going where. Vibe Coding is a new term that was recently introduced and is defined as an AI dependent programming method where someone can put in a few sentences to a large language module (LLM for short) and it will generate code. This allows novice users to produce, or attempt to produce software without extensive training, which seems to take the hard work out of what people have spent an entire lifetime honing their craft.
Now this has definitely raised some concerns with a fundamental lack of understanding and accountability based on the person that is attempting to use this as their tool for creating all of their work. It can lead to hours of debugging that the LLM cannot understand and even allow vulnerabilities in the code that a software engineer would know to avoid. Another issue is that many software engineers work on existing systems and it’s absolutely critical that one understands the underlying code.
There are some software companies right now that actually prohibit the developers from using any AI generated code in the slightest, which makes perfect sense. Especially when it doesn’t have a way of understanding proprietary API unless it’s fed that information.
Should coders be allowed to use it?
This a key question companies are asking. On one hand, it can be used as tool to either help troubleshoot or build a skeleton of a program that can take a little massaging with the right know-how. On the other, it can be a crutch to some people to the point that they don’t know how to code without it.
Whether you like it or not, it’s here to stay. It can be used with things like intelliJ or VS code, seamlessly. We should learn to embrace it, but we need the fundamentals before using it. If you learn to build things with your hands without power tools but use them to help speed up your productivity, that’s great! It’s good to potentially help spell out odd lines of code and what the purpose of that actually is. Either way, it’s main purpose should be a tool, not a replacement for thinking.
Pitfalls of using it without context
For example, I’ve asked chatGPT to build me a hysteresis block without any other context. Here was the response.
After this, I asked to give me the java code for one and it gave me this:
If we break down this code, we have our variable instances at the top, an enum (Heat/Cool), a constructor that passes a setpoint, hysteresis (diff), the operating mode, and the output (default value is false) when this is created, a method to read the current temperature and applies the logic to turn the heating and cooling mode on or off, some getters and setters. This looks like a complete code! However, will this work as is in Niagara? Absolutely not. It is not structured in a way it could be accepted. Which leads me to my biggest point.
You must tell the LLM what to do
You must give explicit instructions or else it doesn’t understand the actual application. For example, common hysteresis blocks in HVAC programming usually have an input, on setpoint, off setpoint, output, and direction (direct or reverse acting). This means we must give the LLM more and more information. So the next step I did was to give it more information on what the object needed to do:
Here is the code it gave me:
So this is very close to a code I would want to use in a Niagara program and as you can see, I gave the LLM a little more direction to go. We could use this code for the most part and massage a small amount to get it working in a program object, but let’s see what the LLM can do if we give it even more information:
As you can see, I gave it even more specifics on how a Niagara program object is more or less constructed. What my goal here to achieve is to see if it give me the appropriate getters and setters, and in addition, provide a way to monitor for valid values in the system. To me, that’s what is truly missing from the code.
Response from chatGPT:
Now that is impressive! There are certain things that chatGPT doesn’t understand.
Since the source tab generates our getters and setters for us, we don’t need them in the code. In addition, we no longer need to reference the primitives if our objects, so we can refer to them directly (if they are like a baja:boolean for example) or use getValue() versus getDouble(). Also since we are using baja:StatusNumeric the correct method is getStatus().isValid(). Since we know these things and chatGPT still doesn’t. We can tell it to modify itself. There are some other things we need to tell but small steps at a time.
This seems more reasonable but still not 100% correct. Because output is a BStatusBoolean we can use getOutput.setValue() instead. In addition, input would be getInput(). The same thing goes along for the onSetpoint and offSetpoints. We would reference the getters and setters here.
WAIT… THERE ARE TWO ANSWERS?
Yes! ChatGPT can do this for a few reasons:
-
The model isn’t a reliable source of factual information. Its job is to generate text for you which resembles a response to your input.
-
The slightest change in grammar, phrasing, and even punctuation can prompt a different effect on the output. It’s more important than you expect!
-
There is an element of randomness to the model’s replies. Since it’s not a “set in stone” model, its answers will usually be different in new threads the prompt forces it to respond in a specific manner.
To show you that they are different:
Response 1 code:
Response 2 Code:
Response 2 is the closest thing to what we need. We didn’t need to call methods like BStatusBoolean.make(). We can use getOutput().setValue(). There’s one more error here at but let’s correct that when we compile this code.
First things first! Create your slots of your program object!
Second, paste the code into the Edit tab and compile and let’s review the errors.
Let’s talk about dereferencing. That’s what happens when we use the . operator to access a method or property of an object. Pretty much this error is saying that the method .setValue() doesn’t exist on the boolean because it’s a primitive, not an object, so that’s why we are getting this error.
Primitives are the most basic data type in java. They’re not objects at all. They’re simple, raw values stored directly in memory. Java can provide something called a wrapper class for each primitive data type. So boolean becomes Boolean or BBoolean (from a Baja type). So java will automatically convert between primitives and their wrapper types, called autoboxing (primitive to object) and unboxing (object to primitive). So since we had boolean for isReverseActing, we can autobox it by setAction(isReverseActing) to gets autoboxed into a BBoolean.
So if we change that line to:
We can compile without any errors:
After that we can test the code:
As you can see, our temperature is at 76 and we will turn on above 72 and below 68, making this direct acting.
With the screenshot above, we can see the OffSp is greater than the OnSp, making the action reverse!
NOTE: In the code, I could’ve added prior to this that my input needed to be greater than or equal to (or less than or equal to) in the code beforehand. Again, those are things you would have to tell chatGPT.
Conclusion
While chatGPT can be a tool, it takes asking the right questions and leading it directly where you want to go. It cannot generate it all on its own. So I do stress that you take the time to learn to code and use chatGPT wisely. Don’t rely on it entirely.
As always, until next time!
Code pasted below:
/* Auto-generated ProgramImpl Code */
import java.util.*; /* java Predefined*/
import javax.baja.nre.util.*; /* nre Predefined*/
import javax.baja.sys.*; /* baja Predefined*/
import javax.baja.status.*; /* baja Predefined*/
import javax.baja.util.*; /* baja Predefined*/
import com.tridium.program.*; /* program-rt Predefined*/
public class ProgramImpl
extends com.tridium.program.ProgramBase
{
////////////////////////////////////////////////////////////////
// Getters
////////////////////////////////////////////////////////////////
public BStatusNumeric getInput() { return (BStatusNumeric)get("input"); }
public BStatusNumeric getOnSetpoint() { return (BStatusNumeric)get("onSetpoint"); }
public BStatusNumeric getOffSetpoint() { return (BStatusNumeric)get("offSetpoint"); }
public BStatusBoolean getOutput() { return (BStatusBoolean)get("output"); }
public boolean getAction() { return getBoolean("action"); }
////////////////////////////////////////////////////////////////
// Setters
////////////////////////////////////////////////////////////////
public void setInput(javax.baja.status.BStatusNumeric v) { set("input", v); }
public void setOnSetpoint(javax.baja.status.BStatusNumeric v) { set("onSetpoint", v); }
public void setOffSetpoint(javax.baja.status.BStatusNumeric v) { set("offSetpoint", v); }
public void setOutput(javax.baja.status.BStatusBoolean v) { set("output", v); }
public void setAction(boolean v) { setBoolean("action", v); }
////////////////////////////////////////////////////////////////
// Program Source
////////////////////////////////////////////////////////////////
public void onExecute() {
// Check validity of input values
if (!getInput().getStatus().isValid() || !getOnSetpoint().getStatus().isValid() || !getOffSetpoint().getStatus().isValid())
{
// Invalidate output if any of the inputs are invalid
getOutput().setValue(false);
return;
}
double inputVal = getInput().getValue();
double onVal = getOnSetpoint().getValue();
double offVal = getOffSetpoint().getValue();
// Determine if the block is reverse acting (on < off)
boolean isReverseActing = onVal < offVal;
// Update action slot to reflect mode
setAction(isReverseActing);
// Get current output value
boolean currentOutput = getOutput().getValue();
// Apply hysteresis logic
boolean newOutput = currentOutput;
if (isReverseActing) {
if (!currentOutput && inputVal <= onVal) {
newOutput = true;
} else if (currentOutput && inputVal >= offVal) {
newOutput = false;
}
} else {
if (!currentOutput && inputVal >= onVal) {
newOutput = true;
} else if (currentOutput && inputVal <= offVal) {
newOutput = false;
}
}
// Set output based on result
getOutput().setValue(newOutput);
}
}