CAN sounds the most applicable in this case. The distances inside a house can be handled by CAN at 500 kbits/s, which sounds like plenty of bandwidth for your needs. The last node can be a off the shelf USB to CAN interface. That allows software in the computer to send CAN messages and see all the messages on the bus. The rest is software if you want to present this to the outside world as a TCP server or something.
CAN is the only communications means you mentioned that is actually a bus, except for rolling your own with I/O lines. All the others are point to point, including ethernet. Ethernet can be made to logically look like a bus with switches, but individual connections are still point to point and getting the logical bus topology will be expensive. The firmware overhead on each processor is also considerably more than CAN.
The nice part about CAN is that the lowest few protocol layers are handled in the hardware. For example, multiple nodes can try to transmit at the same time, but the hardware takes care of detecting and dealing with collisions. The hardware takes care of sending and receiving whole packets, including CRC checksum generation and validation.
Your reasons for avoiding PICs don't make any sense. There are many designs for programmers out there for building your own. One is my LProg, with the schematic available from the bottom of that page. However, building your own won't be cost effective unless you value your time at pennies/hour. It's also about more than just the programmer. You'll need something that aids with debugging. The Microchip PicKit 2 or 3 are very low cost programmers and debuggers. Although I have no personal experience with them, I hear of others using them routinely.
Added:
I see some recommendations for RS-485, but that is not a good idea compared to CAN. RS-485 is a electrical-only standard. It is a differential bus, so does allow for multiple nodes and has good noise immunity. However, CAN has all that too, plus a lot more. CAN is also usually implemented as a differential bus. Some argue that RS-485 is simple to interface to electrically. This is true, but so is CAN. Either way a single chip does it. In the case of CAN, the MCP2551 is a good example.
So CAN and RS-485 have pretty much the same advantages electrically. The big advantage of CAN is above that layer. With RS-485 there is nothing above that layer. You are on your own. It is possible to design a protocol that deals with bus arbitration, packet verification, timeouts, retries, etc, but to actually get this right is a lot more tricky than most people realize.
The CAN protocol defines packets, checksums, collision handling, retries, etc. Not only is it already there and thought out and tested, but the really big advantage is that it is implemented directly in silicon on many microcontrollers. The firmware interfaces to the CAN peripheral at the level of sending and receiving packets. For sending, the hardware does the colllision detection, backoff, retry, and CRC checksum generation. For receiving, it does the packet detection, clock skew adjusting, and CRC checksum validation. Yes the CAN peripheral will take more firmware to drive than a UART such as is often used with RS-485, but it takes a lot less code overall since the silicon handles so much of the low level protocol details.
In short, RS-485 is from a bygone era and makes little sense for new systems today. The main issue seems to be people who used RS-485 in the past clinging to it and thinking CAN is "complicated" somehow. The low levels of CAN are complicated, but so is any competent RS-485 implementation. Note that several well known protocols based on RS-485 have been replaced by newer versions based on CAN. NMEA2000 is one example of such a newer CAN-based standard. There is another automotive standard J-J1708 (based on RS-485) that is pretty much obsolete now with the CAN-based OBD-II and J-1939.
If you don't want to use API, and strictly want to use AT mode, then I suggest you simply put a destination prefix string at the beginning of each of your messages, and then broadcast all messages to all end-nodes.
On the receiving end-nodes, write some code to check whether the destination prefix string of a received message matches that particular end-node's address/name (which you can assign randomly yourself in code).
I don't think it's a good idea to change ATDL dynamically for each message. Not only might it affect the timing and require re-pairing but also remember that ATDL is written to the Xbee's EEPROM -- which only allows a finite number of rewrites.
UPDATE: More details regarding implementation (as requested by OP):
If you have setup Xbees already, then it should be extremely easy. Imagine there are five people at a loud party, and you have to ask one of them to come near you -- how do you do it from where you are? You yell out their name first, then say what you want to say. So, "John, come here." (Or if two people, "John and Mary, come here.")
Everyone hears it but only John will think it concerns him, so he will listen to the rest of the message, then he will act.
Likewise, let's say you want to send a message to any of the "end-nodes" in your network. First assign all of them addresses, let's say 1 to 5. Now, from the central/base Xbee, you broadcast a message (i.e., it goes to everyone), for example, "01,03>76".
- The destination addresses are everything before the ">" (you could use any symbol).
- So, 01 and 03 are the addresses of the Xbee destinations you intend to communicate to.
- And the actual content of the message is everything after the ">".
- So, "76" or "abc" or whatever will be the message you intend to send to Xbees 01 and 03.
And similarly, on the LISTENING Xbees (not the central/base Xbee, but instead the end-nodes), you simply put an "if"-condition to check if the message received is for that Xbee. Here is some pseudocode:
MyAddress = "01" [this will be different for each end-node Xbee]
Read for any Xbee received messages
if (XbeeReceivedMessageString contains MyAddress before ">")
{
read the rest of the message and do whatever you need to do with it.
}
else
{
do nothing/ignore.
}
(If you need help with setting up and learning about Xbees, just Google for it. An easy way to get started might be by searching for "Xbee Arduino tutorials".)
Best Answer
Since this question was asked, the situation has changed a little: as Jennic is now fully absorbed by NXP, which also acquired Freescale, there are a couple more options to choose between.
Sticking with the JN516x family, you can now find some pluggable modules with header pins, such as:
DORJI JN516X JN5168 Zigbee module DZM5168M
MeshBee
As an alternative, there is the formerly Freescale Kinetis KW21Z with an ARM Cortex M0+ and an 802.15.4 transceiver with an official development kit (FRDM-KW41Z) made of two boards, for just above 100$. Honestly I couldn't find anything any cheaper than that in a quick search on the web.