Chevy S10, Blazer, GMC Sonoma hunting, high hanging idle while moving fix

This post has been updated 4/20/20 after I replaced the throttle body.

I recently acquired a 2000 GMC Sonoma for the princely sum of $1900, which came with a few $1900 car problems.

The most annoying of which for actually driving the vehicle was a really weird hanging and hunting idle behavior. The following things would happen:

  • When I got the vehicle, I noticed the idle would jump up to 1800 RPM sometimes while driving with clutch out. When the wheel speed got low enough, it would drop back to normal.
  • I cleaned the throttle body and it got worse.
  • I replaced the IAC and it got worse. The idle would sometimes hang at 1800, 2000, or even 3000 RPM while operating the vehicle. Once the vehicle slowed down the idle would return to ~700 RPM.
  • The idle would hunt while I was driving with clutch in or in neutral, with spark timing varying wildly between 0 and 35 degrees while the RPM oscillated. This happened especially when the engine was hot-started and the Intake Air Temp sensor was heat soaked. I have a video showing this behavior on the HPTuners readout.
  • The idle was high even with the IAC fully extended (reading 0 units on the scan tool).

I believe this applies primarily to the 2000 and earlier model year vehicles but may apply to later ones as well (there is different software and compensation tables on 2001 and up).

After spending $700 on various tuning implements (GM Tech 2 and HPTuners software and dongle), reading out data, learning the ins and outs of the GM PCM control algorithms in the 2000 MY vehicles, I have figured out what the hell is going on.

The TL;DR Fix

This issue is caused by an IAC that isn’t behaving to spec, which seems to be an IAC reading ~60 counts on a Tech 2 with the following conditions:

  • Engine Coolant temp normal and the engine/oil is fully warmed up
  • Idle at 650 RPM
  • Spark timing 17-19 degrees

To fix this, you need to;

  • Back out the throttle plate stop screw all the way and check the IAC count. It should be >60 counts. If that doesn’t work:
  • Check for a vacuum leak which results in the IAC being fully extended at idle. Plug the PCV hose with a screw wrapped in electrical tape, cap the vacuum nipple that runs to the brake booster, check the intake manifold, check the seals after the MAF and the throttle body shaft.
  • If everything looks normal vacuum-wise but your IAC is still reading lower, you need to swap the IAC for an OEM part. Non-OEM parts seem to have a different ratio of IAC to counts to airflow, and the GM PCM has hard-coded values for IAC park position and ratio of IAC counts to % airflow. The easiest way I found was a junkyard throttle body with IAC and TPS still attached for $40 shipped on eBay, and I contacted the seller first to confirm there was no play in the shaft.

The GM PCM is not prepared for an IAC value out of spec and goes haywire due to a few causes which I’ll talk about later. You need to adjust the system until you get the IAC to read about 60 counts in park/neutral with RPM at 650 and engine up to temperature and the problem should vanish.

The long-winded version:

Step 1: Double check for Vacuum leaks:

  1. Plug the PCV valve hose with a screw wrapped in electrical tape. I dropped 150 RPM when this was plugged.
  2. Plug the vacuum nipple that drives the brake booster and check for difference in idle. I did not notice a difference in idle speed after I did this, indicating that there was no vacuum leak in the brake/transfer case/climate control system. Also, check the climate control holds in the defrost position after you turn off the vehicle. If everything is functioning properly, there is a check valve that prevents the vacuum from leaking out of the vacuum cylinder.
  3. Maybe replace decrepit vacuum lines that look sad.
  4. Worn throttle body can let air in through the shaft. Double check for that, replace, and/or slather the shaft with grease on the outside. You’ll need to peel the spring back. I ended up just ordering a junk yard part on eBay which came with an OEM IAC and TPS bolted in.
  5. You can create a DIY smoke machine. Pump smoke into the vacuum nipple below the PCV valve and see where smoke comes out. Could be intake manifold etc. Also worth pumping smoke in after the MAF (you can use a nitrile glove with the finger cut off to pump smoke into the intake hose; just wrap the wrist around the hose and use the finger with a rubber band or hose clamp around the smoke hose).
  6. Double check the seal around the plastic throttle body adapter piece that connects to the intake hose. Slather with grease if that’s leaking.

Step 2: Back out the Throttle Body screw until the IAC has some wiggle room

Using a scan tool you can check the IAC position. Supposedly the IAC should be close to 60. The problem got better when I got the IAC to 30 and I started to notice difficulty starting the vehicle while hot once the IAC got to 76 counts at idle. The GM PCM seems to expect a certain behavior of the IAC — the “park position” is hard coded based on engine coolant temp in the PCM, so

  • if you adjust it too low you get a large flare up (1500-2000 RPM) at engine start and then it ratchets down once the PID feedback control kicks in.
  • If you adjust it too high the engine will not be getting enough air right after you start it when the ECT is at operating range. The result is a slow start when engine is up to temp.
  • If the throttle plate screw is dialed in, the IAC runs out of space to lower the idle it causes the GM PCM to compensate with spark timing.

FYI — cleaning the throttle body can make the “previous owner adjusted the throttle plate screw to compensate for a failed IAC issue” worse since it can allow more air to seep in for a given screw position. Clean the TB before you adjust the screw, then adjust the screw back to close the plate.

Step 3: high quality IAC, double check MAP and MAF

I’m not sure if this is important, but using a $7 IAC from eBay made this behavior worse. Switching to a $100 IAC from a reputable brand resulted in less problems. An OEM IAC from the junk yard seems to be the best bet since the PCM can’t compensate for different IAC count-to-airflow ratios.

Also make sure there aren’t leaks in the intake hose or on the other gaskets.

Double check the MAP and MAF report reasonable values.

The full story

As best I can discern the problem in my vehicle was caused by:

  1. There was an issue with the IAC which limited its motion.
  2. The previous owner adjusted the TB screw such that the car would idle more or less normally with the limited IAC range.
  3. This confused the computer and resulted in some of the high idle behavior (more detail below).
  4. I noticed this behavior and tried to fix it. The first recommendation for high idle is sticky throttle plate, so I cleaned the throttle body. This allowed more air through and raised the idle, making the problem worse.
  5. I brought it to a shop, which noticed the IAC code but noticed that the problem got even worse when the IAC was replaced.
  6. I carried on futzing with it, reading out more data, getting traces from the tuner chip, noticing the PCV was leaking a bit. etc. Finally realized I could adjust the TB screw.
  7. Using different brand IACs has different results. OEM IAC seems necessary.

What’s the stupid PCM doing and why does it react like this

As far as I can tell, several things contribute to the weird behavior when the GM PCM is operating out of range:

  1. When the PCM cannot reach idle at full IAC extension, it starts to perturb the spark timing in order to lower the RPM further. The timing advance should be like 17-19 degrees at idle but it can be reduced if the idle is offset. Ordinarily, the intent is that the spark timing could be used to refine the speed on quick intervals, but when the IAC runs out of room that will result in more or less permanent degree shifting. So the result is that at normal spark timing the idle will be quite high even if the PCM can get the idle closer to correct with spark tweaking.
  2. Hanging idle: The GM PCM cannot deal with weird IAC count to airflow ratios. As a result, in some regions of its operation it will hang the idle. I’m not entirely clear as to why this happens, but it may have something to do with the fact that the GM uses hybrid MAF and VE mode which it will toggle back and fourth between. It also uses different cells of operation on dynamic airflow depending upon the throttle position and whether the PCM thinks it’s in idle mode. If the GM PCM doesn’t think it’s in idle, it won’t enter the idle cell #2. See the HPTuners documentation on GM Dynamic Airflow calculations. (cached pdf)
  3. Slow decaying idle: The PCM in the 2000 Sonoma has a “throttle follower” feature designed to more gently lower the throttle. Under normal circumstances: if you are accelerating, the IAC valve opens proportionally to the RPM to let more air in given a fixed set of tables it’s programmed with. However, the fact that the IAC is regulated proportional to the RPM and totally ignorant of the throttle position sensor (TPS) means that it can be unstable. So it adds 75-120 counts of air relative to 0, the spark timing is back to “normal” and the result is that the idle can hang since the IAC opening of 100 counts is sufficient to hold the engine at 2000+ RPM where it’s programmed to open 100 counts.
  4. Hunting Idle Spark: the computer appears to be swapping back and fourth between the idle spark table and the main spark table. The result is that the spark flies from 35 down to 0. The logic here is a bit weird, but it seems to be a follow-down effect from the computer being confused about whether the car is at idle when the IAC is open to 100+, the throttle is closed, but the vehicle is moving quickly. During my recording, the IAC never closed but the spark timing kept jumping around.
  5. Hunting idle MAF vs VE?: The GM PCM uses a hybrid VE and MAF mode, switching between the VE mode and MAF mode. Volumetric Efficiency (VE mode) uses Intake Air Temperature (IAT) sensor, engine RPM and volume, and the Manifold Absolute Pressure sensor to calculate fuel. MAF mode relies on the Mass Airflow sensor to provide an absolute airflow amount to calculate required fuel. When the IAT is heat soaked (reading very high because the car was parked with a hot radiator that heat up the IAT sensor from the outside of the hose), the VE calculation will be thrown off. During some conditions, it would appear that the PCM switches between the modes and oscillates between them. I believe this is related to the hanging idle problem. In particular, the GM 2000 and earlier PCM appears to compensate poorly for the heat soaked IAT. Some people have relocated their MAP sensor to the intake manifold or another region where it will not be heat soaked as easily. It may be possible to swap in a later PCM but that might require shenanigans.

Note: the GM troubleshooting tool does mention the Throttle Body adjustment screw. But it was confusing because you’re not ordinarily supposed to adjust it.

Anyways, feel free to drop me a comment if this works/doesn’t work for you.

Fixing the slowly decaying idle

The GM PCM is programmed with a rather slow decay on the throttle follower and a high airflow to hold the IAC open while the engine is operating. Basically:

  1. User is holding the accelerator down.
  2. The IAC opens proportional to the RPM.
  3. User releases the throttle.
  4. The IAC is programmed to decay slowly to prevent backfire etc.

This behavior can be considered annoying. Additionally, this PCM has a higher value while the vehicle is in gear to keep the driveshaft from clunkying when you release the accelerator. The result is much less engine braking in some circumstances.

To tune this away, I’m going to try:

  • Equalizing the “In Gear” and “Neutral” throttle follower tables.
  • Doubling the decay rate of the throttle follower.
  • Perhaps also decreasing both throttle follower tables by 25% or so to start.

I’ll report back when that’s done.

Goal Zero Yeti Local WiFi REST API

Update: Goal Zero generously provided me with a Postman file to show all the routes supported by the Yeti. I’ve added info on that to the bottom.

I have acquired a new Goal Zero Yeti 3000 and was curious how to use its WiFi functionality for evil. The app is acceptable, but I’ve discovered you can query the local REST API using some glorious wireshark monitor mode.

Basically, hit http://GOAL_ZERO_IP/state. GET returns:

{
"thingName": "yetiXXXXXXXX",
"v12PortStatus": 1,
"usbPortStatus": 1,
"acPortStatus": 1,
"backlight": 1,
"app_online": 1,
"wattsIn": 245.3,
"ampsIn": 21.9,
"wattsOut": 161.3,
"ampsOut": 14.4,
"whOut": 3682,
"whStored": 2070,
"volts": 11.2,
"socPercent": 69,
"isCharging": 1,
"timeToEmptyFull": 681,
"temperature": 30,
"wifiStrength": -37,
"timestamp": 317529,
"firmwareVersion": "0.7.2",
"version": 2
}

and POST can be used with this JSON:

POST /state HTTP/1.1
Host: 10.1.1.1
Content-Type: application/json
User-Agent: YetiApp/1340 CFNetwork/1125.2 Darwin/19.4.0
Connection: keep-alive
Accept: application/json
Accept-Language: en-us
Content-Length: 19
Accept-Encoding: gzip, deflate
Cache-Control: no-cache

and the payload to turn off USB:

{"usbPortStatus":0}

Or to set the 12V port:

{"v12PortStatus":0}

Or you can set all 3 states at the same time:

{"v12PortStatus":0,
"usbPortStatus":0,
"acPortStatus": 1}
  • In direct connect mode, it creates a WiFi network and the phone queries its HTTP server at /state. GET returns status and POST can be used to change settings.
  • In remote mode (called “anywhere connect”), it joins your network and phones home to AWS _but_ it can still be queried over the local HTTP server.

Also some other routes:

GET /sysinfo HTTP/1.1
Host: 10.1.1.1
Accept-Encoding: gzip, deflate
Accept: application/json
User-Agent: YetiApp/1340 CFNetwork/1125.2 Darwin/19.4.0
Accept-Language: en-us
Cache-Control: no-cache
Connection: keep-alive
{ "name": "yetiXXXXXXXXX", "model": "Yeti 3000", "firmwareVersion": "0.7.2", "macAddress": "XXXXXXXX", "platform": "esp32" }
POST /join-direct HTTP/1.1
Host: 10.1.1.1
Content-Type: application/json
Content-Length: 0
Connection: keep-alive
Accept: application/json
User-Agent: YetiApp/1340 CFNetwork/1125.2 Darwin/19.4.0
Accept-Language: en-us
Cache-Control: no-cache
Accept-Encoding: gzip, deflate

When queried on my laptop, returned:

{ "name": "yetiXXXXXX", "model": "Yeti 3000", "firmwareVersion": "0.7.2", "macAddress": "XXXXXXXX", "platform": "esp32", "state": {
  "thingName": "yetiXXXXXXXX",
  "v12PortStatus": 1,
  "usbPortStatus": 1,
  "acPortStatus": 1,
  "backlight": 1,
  "app_online": 1,
  "wattsIn": 229.6,
  "ampsIn": 20.5,
  "wattsOut": 142.2,
  "ampsOut": 12.7,
  "whOut": 3743,
  "whStored": 2100,
  "volts": 11.2,
  "socPercent": 70,
  "isCharging": 1,
  "timeToEmptyFull": 552,
  "temperature": 30,
  "wifiStrength": -39,
  "timestamp": 319152,
  "firmwareVersion": "0.7.2",
  "version": 2
} }

Other Routes from Goal Zero

Quick summary

  • GET /sysinfo – gives system info from the ESP32
  • POST /factory-reset with “{}” body does a factory reset
  • GET /rpc/Sys.Reboot will trigger a reboot

GET/POST to /loglevel

{
  "app": 3,
  "ota": 3,
  "ota_cleanup": 3,
  "mqtt": 3,
  "mqtt_shadow": 3,
  "mqtt_jobs": 3,
  "yeti": 4,
  "wifi": 3,
  "http_server": 3,
  "http_client": 3,
  "main": 3,
  "uart": 3,
  "pic_btldr": 3,
  "chain": 3,
  "sys": 3
}

POST to /join to join the wifi

{
"wifi": {
"name": "NetworkName",
"pass": "Password"
},
"iot": {
"env": "prod",
"hostname": "a1xyddj5i8k7t5-ats.iot.us-east-1.amazonaws.com",
"endpoint": "https://yeti-prod.goalzeroapp.com/v1/thing"
}
}

GET to /wifi to show the available wifi networks the GZ can see

{
    "NickPixel": {
        "db": -38
    },
    "networky-saved": {
        "db": -43,
        "saved": true
    },
    "something-else": {
        "db": -67
    }
}

POST to /password-set to change the Yeti password

{
"new_password": "ABCDEFGH"
}

POST to /join-direct to join direct (not clear exactly what this does when in cloud mode)

POST to /start-pair again, not clear exactly what this does

Note: when I POST to /state the yeti began sending its network again but is still joined to the main WiFi network. Not sure if there’s a good configuration for local network only without IoT phone home feature.